home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2001 September / PC-WELT 9-2001.ISO / software / hw / brennen / flask_src.exe / Subpic / Subpicba.cpp < prev   
Encoding:
C/C++ Source or Header  |  2000-05-13  |  11.5 KB  |  427 lines

  1. /* 
  2.  *  StreamDetector.cpp: implementation of the CStreamDetector class.
  3.  *
  4.  *    Copyright (C) Alberto Vigata - January 2000 - ultraflask@yahoo.com
  5.  *
  6.  *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
  7.  *    
  8.  *  FlasKMPEG is free software; you can redistribute it and/or modify
  9.  *  it under the terms of the GNU General Public License as published by
  10.  *  the Free Software Foundation; either version 2, or (at your option)
  11.  *  any later version.
  12.  *   
  13.  *  FlasKMPEG is distributed in the hope that it will be useful,
  14.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.  *  GNU General Public License for more details.
  17.  *   
  18.  *  You should have received a copy of the GNU General Public License
  19.  *  along with GNU Make; see the file COPYING.  If not, write to
  20.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  21.  *
  22.  */
  23.  
  24. #include <crtdbg.h>
  25. #include "subpic.h"
  26. extern "C"
  27. {
  28. #include "..\video\global.h"
  29. }
  30.  
  31. struct subpic_t {
  32.     unsigned char *bitmap;
  33.     int x, y; /* dimensions */
  34.     int sX, sY; /* coordinates */
  35.     i64 start, stop; /* start and stop time */
  36.  
  37.     unsigned char colors[4]; /* palette */
  38.     unsigned char alpha[4]; /* alpha channel */
  39.     struct subpic_t *next, *prev;
  40. };
  41.  
  42. static struct subpic_t *pics = NULL;
  43.  
  44. /* grab a nibble from buf */
  45. static unsigned char grab_nibble(const unsigned char *buf, unsigned &offset, bool &aligned)
  46. {
  47.     unsigned char c;
  48.     if(aligned) c = buf[offset] >> 4;
  49.     else {
  50.         c = buf[offset] & 0xF;
  51.         offset++;
  52.     }
  53.     aligned = !aligned;
  54.  
  55.     return c;
  56. }
  57.  
  58. static void free_subpic(struct subpic_t *p)
  59. {
  60.     if(p == NULL) return;
  61.     if(p->bitmap) free(p->bitmap);
  62.     free(p);
  63. }
  64.  
  65. /* free all subpics */
  66. void subpic_free(void)
  67. {
  68.     struct subpic_t *s;
  69.     for(s = pics; s; s=s->next) {
  70.         free_subpic(s);
  71.     }
  72.     pics = NULL;
  73. }
  74. #include "..\Input\IFOParser\IFOParser.h"
  75.  
  76. static char palette[16][4];
  77. extern CIFOParser *IFOGlobal;
  78. static void subpic_apply(VBitmap *p, i64 tm, struct subpic_t *s)
  79. {
  80.     for(int i = 0; i < 16; i++) {
  81.         int crv = 117504, cbu = 138453, cgu = 13954, cgv = 34903;
  82.  
  83.         int  u = (unsigned char)IFOGlobal->pgcs[0].clut[i][3] - 128;
  84.         int  v = (unsigned char)IFOGlobal->pgcs[0].clut[i][2] - 128;
  85.         int  y = 76309 * ((unsigned char)IFOGlobal->pgcs[0].clut[i][1] - 16);
  86.  
  87.         palette[i][0] = Clip[(y + crv*v + 32768)>>16];
  88.         palette[i][1] = Clip[(y - cgu*u - cgv*v + 32768)>>16];
  89.         palette[i][2] = Clip[(y + cbu*u + 32786)>>16];
  90.     }
  91.  
  92.     for(int x = 0; x < s->x; x++) {
  93.         for(int y = 0; y < s->y; y++) {
  94.             int X = s->sX + x;                /* index into p of this pixel of the subpic */
  95.             int Y = p->h - (s->sY + y);
  96.             
  97.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  98.  
  99.             int alpha = s->alpha[pcolor];
  100.             if(alpha == 0x0) continue; /* don't waste time on completely transparent pixels */
  101.  
  102.             pcolor = s->colors[pcolor]; /* convert subpic palette index into master palette */            
  103.  
  104.             unsigned char color[2][4];
  105.             memcpy(color[0], &p->data[Y * p->w + X], 4); /* original color */
  106.             memcpy(color[1], palette[pcolor], 4);        /* real subpic color */
  107.  
  108.             for(int i = 0; i < 3; i++) {
  109.                 int x, y;
  110.  
  111.                 x = (color[0][i] * (0xFF - alpha)) / 0xFF;
  112.                 y = (color[1][i] * alpha) / 0xFF;
  113.  
  114.                 color[0][i] = x + y;
  115.             }
  116.  
  117.             p->data[Y * p->w + X] = (color[0][0] << 16) + (color[0][1] << 8) + (color[0][2]);
  118.         }
  119.     }
  120. }
  121.  
  122. void subpic_apply(VBitmap *p, i64 tm)
  123. {
  124.     // tm, current time
  125.     struct subpic_t *s, *next;
  126.     for(s = pics; s; s=next) {
  127.         next=s->next;
  128.  
  129.         if(tm < s->start) continue; /* not yet */
  130.  
  131.         if(tm < s->stop) {
  132.             subpic_apply(p, tm, s);
  133.             continue;
  134.         }
  135.         /* pic done */
  136.         if(s->prev) s->prev->next = s->next;
  137.         if(s->next) s->next->prev = s->prev;
  138.         if(s == pics) pics=pics->next;
  139.         next = s->next;
  140.         free_subpic(s);
  141.     }
  142. }
  143.  
  144. /* Parse a buffer into a bufpic.  Return -1 on error (can't parse), 0 on incomplete
  145.  * buffer, or 1 on success. On success, the subpic will be in pic; on error, pic
  146.  * may have a bitmap allocated ( != NULL), and should be freed.
  147.  *
  148.  * buf is the actual buffer; bufsiz is its length.
  149.  * tm is the time, in ms, of this packet, from the start of the stream; used for
  150.  * computing start and stop times. */
  151.  
  152. static int do_subpic_decode(const unsigned char *buf, size_t bufsiz, i64 tm,
  153.                             struct subpic_t *pic)
  154. {
  155.     unsigned dataLen;
  156.     
  157.     if(bufsiz < 4) return -1; /* way too short */
  158.     /* grab the length of the data packet */
  159.     dataLen = (buf[2] << 8) + buf[3];
  160.  
  161.     if(dataLen > bufsiz) return 0; /* incomplete */
  162.  
  163.     /* set default values */
  164.  
  165.     memset(pic, 0, sizeof(struct subpic_t));
  166.     pic->x = pic->y = pic->sX =  pic->sY = -1; /* required values */
  167.     pic->start = pic->stop = -1;
  168.  
  169.     /* parse the control packet */
  170.     unsigned offset[2];
  171.     bool control_done = false;
  172.     unsigned i = dataLen;
  173.  
  174.     /* for dupe offset checking */
  175.     unsigned offsets_done[255];
  176.     int offsets_done_n = 0;
  177.  
  178.     while(!control_done) {
  179.             unsigned start = i; /* offset of this sequence */
  180.             
  181.             /* decode each sequence of the control block */
  182.             bool control_sequence_done = false;
  183.  
  184.             if(i+4 >= bufsiz) return -1;
  185.  
  186.             i64 seq_time = 0;            
  187.             seq_time += buf[i++] << 8;
  188.             seq_time += buf[i++];
  189.             seq_time *= (27000000.0 / 88.0); /* it's in 1/100ths of a second; we want refrences to 
  190.                                 the 27Mhz MPEG2 reference clock*/
  191.             
  192.             unsigned next = 0; /* offset to the next sequence, or to this one if last */
  193.             next += buf[i++] << 8;
  194.             next += buf[i++];
  195.             if(next > bufsiz) return 0; /* incomplete */
  196.  
  197.             /* if it's the same as this, then this is the last */
  198.             if(next == start) control_done = true;
  199.             
  200.             /* if next is in the data packet, we have a problem */
  201.             if(next < dataLen) {
  202.                 _RPT2(0, "Invalid next %u (dataLen %u)\n", next, dataLen);
  203.                 return -1;
  204.             }
  205.  
  206.             /* make sure we're not looping */
  207.             for(int n = 0; n < offsets_done_n; n++) {
  208.                 if(offsets_done[n] == start) {
  209.                     /* oops */
  210.                     _RPT1(0, "next %u encountered twice; looping\n", next);
  211.                     return -1;
  212.                 }
  213.             }
  214.             /* add after the check: it's OK to receive the *current* start as
  215.              * the next (it indicates last packet */
  216.             offsets_done[offsets_done_n++] = start;
  217.             
  218.             while(!control_sequence_done) {
  219.                 unsigned char c;
  220.                 if(i >= bufsiz) return -1;
  221.                 c = buf[i++];
  222.                 bool aligned = true;
  223.  
  224.                 switch(c) {
  225.                 case 1: /* start time */
  226.                     pic->start = seq_time + tm;
  227.                     break;
  228.  
  229.                 case 2: /* stop time */
  230.                     pic->stop = seq_time + tm;
  231.                     break;
  232.  
  233.                 case 3: {
  234.                     /* palette */
  235.                     if(i+1 >= bufsiz) return -1;
  236.                     for(int p = 0; p < 4; p++) {
  237.                         pic->colors[3-p] = grab_nibble(buf, i, aligned);
  238.                     }    
  239.                     
  240.                     break;
  241.                 }
  242.                 case 4: {
  243.                     /* transparency palette (?) */
  244.                     if(i+1 >= bufsiz) return -1;
  245.  
  246.                     /* we want 8 bit alpha, not 4, for future features */
  247.                     for(int p = 0; p < 4; p++) {
  248.                         /* this is a silly way to do this, but I'm drawing a blank
  249.                          * as to a cleaner way, and this is accurate, so ... */
  250.                         pic->alpha[3-p] = (int)( ((double)grab_nibble(buf, i, aligned) / 15.0) * 255);
  251.                     }
  252.  
  253.                     break;
  254.                 }
  255.                 case 5: /* image coordinates */
  256.                     /* width */
  257.                     int endX, endY;
  258.                     if(i+5 >= bufsiz) return -1;
  259.     
  260.                     pic->sX = (grab_nibble(buf, i, aligned) << 8) + 
  261.                               (grab_nibble(buf, i, aligned) << 4) +
  262.                               grab_nibble(buf, i, aligned);
  263.  
  264.                     endX = (grab_nibble(buf, i, aligned) << 8) + 
  265.                            (grab_nibble(buf, i, aligned) << 4) +
  266.                               grab_nibble(buf, i, aligned);
  267.  
  268.                     pic->sY = (grab_nibble(buf, i, aligned) << 8) + 
  269.                               (grab_nibble(buf, i, aligned) << 4) +
  270.                               grab_nibble(buf, i, aligned);
  271.                     
  272.                     endY = (grab_nibble(buf, i, aligned) << 8) + 
  273.                            (grab_nibble(buf, i, aligned) << 4) +
  274.                               grab_nibble(buf, i, aligned);
  275.     
  276.                     pic->x = 1 + endX - pic->sX;
  277.                     pic->y = 1 + endY - pic->sY;
  278.     
  279.                     break;
  280.                 case 0x06: /* image 1 / image 2 offsets */
  281.                     if(i+1 >= bufsiz) return -1;
  282.                     offset[0] = ((unsigned int)buf[i++]) << 8;
  283.                     offset[0] += buf[i++];
  284.                     offset[1] = ((unsigned int)buf[i++]) << 8;
  285.                     offset[1] += buf[i++];
  286.                     break;
  287.                 case 0x07: /* unknown; appears to be 3 bytes */
  288.                     if(i+2 >= bufsiz) return -1;
  289.                     i += 3;
  290.                     break;
  291.     
  292.                 case 0xff: /* end of sequence */                    
  293.                     control_sequence_done = true;
  294.                     break;
  295.  
  296.                 default:
  297.                     /* we can't continue parsing past unknown commands
  298.                      * because we need their length.  we can try to display
  299.                      * them anyway, hoping we already have sufficient data--
  300.                      * if we don't, we'll bail anyway.  at least in my test DVDs,
  301.                      * control sequences appear generally sorted numerically, so
  302.                      * unless we hit c == 0 somehow, we might be OK */
  303.                     _RPT1(0, "Unknown subpic command: %2.2x\n", c);
  304.                     control_done = control_sequence_done = true;
  305.                 }
  306.             }
  307.             i = next;    
  308.     }
  309.  
  310.     /* sanity */
  311.     if(pic->x == -1 || pic->y == -1 || pic->sX == -1 || pic->sY == -1 ||
  312.         pic->start == -1 || pic->stop == -1) {
  313.         /* some required piece of data is missing */
  314.         _RPT0(0, "subpic data missing\n");
  315.         return -1;
  316.     }
  317.  
  318.     /* now we can alloc the bitmap */
  319.     pic->bitmap = (unsigned char *)malloc(pic->x * pic->y);
  320.     memset(pic->bitmap, 0, pic->x * pic->y);
  321.  
  322.     int x = 0, y = 0;
  323.     /* note: all Y wrapping is done in twos, since the pic is interlaced.
  324.      * do even.scanlines first, then odd
  325.      */
  326.     
  327.     int state = 0;
  328.     bool aligned = true;
  329.     if(offset[0] >= bufsiz) return -1;
  330.     if(offset[1] >= bufsiz) return -1;
  331.  
  332.     i = offset[state];
  333.     while(1) {
  334.         unsigned int val;
  335.  
  336.         do{
  337.             if(i >= bufsiz) return -1;
  338.             val = grab_nibble(buf, i, aligned);
  339.             if(val >= 0x004) break;    /* one-byte */
  340.  
  341.             if(i >= bufsiz) return -1;
  342.             val = (val << 4) + grab_nibble(buf, i, aligned);
  343.             if(val >= 0x010) break;    /* two-byte, 1x .. 3x */
  344.  
  345.             if(i >= bufsiz) return -1;
  346.             val = (val << 4) + grab_nibble(buf, i, aligned);
  347.             if(val >= 0x040) break; /* three-byte, 04x .. 0fx */
  348.             
  349.             if(i >= bufsiz) return -1;
  350.             val = (val << 4) + grab_nibble(buf, i, aligned);
  351.             if(val >= 0x100) break; /* four-byte, 01xx .. 03xx */
  352.             /* four-byte, 00xx */
  353.             if(!aligned) {
  354.                 if(i >= bufsiz) return -1;
  355.                 grab_nibble(buf, i, aligned);
  356.             }
  357.         } while(0);
  358.         int pixNum = val >> 2;
  359.         int color = val & 3;
  360.         if(pixNum == 0) pixNum = pic->x - x; /* line feed */
  361.         if(pixNum + x > pic->x)
  362.             pixNum = pic->x - x; /* shouldn't happen: cap pixNum */
  363.             
  364.         while(pixNum--) {
  365.             pic->bitmap[y * pic->x + x] = color;
  366.             x++;
  367.             if(x == pic->x) {
  368.                 /* wrap */
  369.                 x = 0;
  370.                 y += 2;
  371.                 if(y > pic->y) break;
  372.             }
  373.         }
  374.         if(y >= pic->y) {
  375.             /* hit the bottom */
  376.             state++;
  377.             if(state == 2) break; /* done */
  378.             /* finished even; do odd */
  379.             y = 1;
  380.             i = offset[state];
  381.         }
  382.     }
  383.  
  384.     return 1;
  385. }
  386.  
  387. static unsigned char subPicBuf[64000];
  388. static int subPicLen = 0;
  389.  
  390. int subpic_decode(const unsigned char *buf, size_t bufsiz, i64 tm)
  391. {
  392.     struct subpic_t *pic = new struct subpic_t;
  393.     static i64    start_time;
  394.  
  395.     pic->bitmap = NULL;
  396.  
  397.     memmove(subPicBuf+subPicLen, buf, bufsiz);
  398.     subPicLen += bufsiz;
  399.  
  400.     if(tm!=0)
  401.         start_time=tm;
  402.     int ret = do_subpic_decode(subPicBuf, subPicLen, start_time, pic);
  403.  
  404.     if(ret == -1 || ret > 0) {
  405.         if(ret == -1)
  406.             int z = 1; /* debug breakpoint target */
  407.         subPicLen = 0; /* error or success; clear the buffer */
  408.     }
  409.     if(ret <= 0) {
  410.         /* error or incomplete */
  411.         if(pic->bitmap != NULL) free(pic->bitmap);
  412.         delete pic;
  413.  
  414.         return ret;
  415.     }
  416.  
  417.     /* success; store it */
  418.     pic->next = pics;
  419.     pic->prev = NULL;
  420.     if(pic->next) pic->next->prev = pic;
  421.  
  422.     pics = pic;
  423.  
  424.     return ret;
  425. }
  426.  
  427.