home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2004 March / PCWELT_3_2004.ISO / pcwsoft / flaskmpeg_078_39_src.z.exe / flaskmpeg / Subpic / Subpic.cpp next >
Encoding:
C/C++ Source or Header  |  2002-10-28  |  14.3 KB  |  575 lines

  1. /* 
  2.  *  Subpic.cpp: subpic decoding
  3.  *
  4.  *    Copyright (C) Glenn Maynard - May 2000 - glennm@mediaone.net
  5.  *
  6.  *  With the help of Helmet (ezrd@hotmail.com)
  7.  *
  8.  *  This file is part of FlasKMPEG, a free MPEG to MPEG/AVI converter
  9.  *    
  10.  *  FlasKMPEG is free software; you can redistribute it and/or modify
  11.  *  it under the terms of the GNU General Public License as published by
  12.  *  the Free Software Foundation; either version 2, or (at your option)
  13.  *  any later version.
  14.  *   
  15.  *  FlasKMPEG is distributed in the hope that it will be useful,
  16.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  *  GNU General Public License for more details.
  19.  *   
  20.  *  You should have received a copy of the GNU General Public License
  21.  *  along with GNU Make; see the file COPYING.  If not, write to
  22.  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  23.  *
  24.  */
  25.  
  26. #include <crtdbg.h>
  27.  
  28. #include "subpic.h"
  29. extern "C"
  30. {
  31. #include "..\video\config.h"
  32. #include "..\video\global.h"
  33. }
  34.  
  35. class subpic_t {
  36. public:
  37.   subpic_t(){
  38.     bitmap = NULL;
  39.     frRecons = NULL;
  40.     frReconsOut = NULL;
  41.   }
  42.   ~subpic_t(){
  43.       if(bitmap) delete []bitmap;
  44.     if(frRecons) delete frRecons;
  45.     if(frReconsOut) delete frReconsOut;
  46.   }
  47.  
  48.     unsigned char *bitmap;
  49.     int x, y; /* dimensions */
  50.     int sX, sY; /* coordinates */
  51.     int start, stop; /* start and stop time */
  52.  
  53.     CFrame *frRecons;        /* reconstructed picture */
  54.   CFrame *frReconsOut; /* reconstructed picture in output format */
  55.  
  56.     unsigned char colors[4]; /* palette */
  57.     unsigned char alpha[4]; /* alpha channel */
  58.     class subpic_t *next, *prev;
  59. };
  60.  
  61. #include "..\runstate.h"
  62. extern TRunState rs;
  63. static class subpic_t *pics = NULL;
  64.  
  65. /* grab a nibble from buf */
  66. static unsigned char grab_nibble(const unsigned char *buf, unsigned &offset, bool &aligned)
  67. {
  68.     unsigned char c;
  69.     if(aligned) c = buf[offset] >> 4;
  70.     else {
  71.         c = buf[offset] & 0xF;
  72.         offset++;
  73.     }
  74.     aligned = !aligned;
  75.  
  76.     return c;
  77. }
  78.  
  79. static class subpic_t *free_subpic(class subpic_t *s)
  80. {
  81.     class subpic_t *next;
  82.  
  83.     if(s == NULL) return NULL;
  84.  
  85.     next = s->next;
  86.  
  87.     if(s->prev) s->prev->next = s->next;
  88.     if(s->next) s->next->prev = s->prev;
  89.     if(s == pics) pics=pics->next;
  90.  
  91.   delete s;
  92.  
  93.     return next;
  94. }
  95.  
  96. /* free all subpics */
  97. void subpic_free(void)
  98. {
  99.     while(pics) pics=free_subpic(pics);
  100.  
  101.     pics = NULL;
  102. }
  103.  
  104. /* subpic init  */
  105. /*   A.V. modif */
  106. static unsigned char palette[16][4];
  107. static unsigned char yuvpalette[16][4];
  108.  
  109. void subpic_init( unsigned char (*clut)[16][4] )
  110. {
  111.     // Work out RGB palette from IFO YUV palette
  112.     for(int i = 0; i < 16; i++) {
  113.     // Copy the palette
  114.     palette[i][0] = (unsigned char)(*clut)[i][0];
  115.     palette[i][1] = (unsigned char)(*clut)[i][1];
  116.     palette[i][2] = (unsigned char)(*clut)[i][2];
  117.     palette[i][3] = (unsigned char)(*clut)[i][3];
  118.     }
  119. }
  120.  
  121.  
  122. static void subpic_apply(CFrame *fr, int tm, class subpic_t *s)
  123. {
  124.   // Apply subpic as an overlay. The y coordinate has bottom as origin in subpic.
  125.   if(!s->frReconsOut)
  126.   {
  127.     s->frReconsOut = new CFrame;
  128.     s->frReconsOut->Set( s->x, s->y, FRAME_YV12A );
  129.     s->frReconsOut->SetFrame( s->frRecons );
  130.   }
  131.  
  132.   fr->Overlay(  s->sX, s->sY, s->frReconsOut );
  133. }
  134.  
  135. void subpic_apply(CFrame *fr, int tm)
  136. {
  137.     class subpic_t *s, *next;
  138.  
  139.     for(s = pics; s; s=next) {
  140.         next=s->next;
  141.  
  142.         if(tm < s->start) continue; /* not yet */
  143.  
  144.         if(tm < s->stop) {
  145.             subpic_apply(fr, tm, s);
  146.             continue;
  147.         }
  148.  
  149.         /* pic done */        
  150.         next = free_subpic(s);
  151.     }
  152. }
  153.  
  154. /* Parse a buffer into a bufpic.  Return -1 on error (can't parse), 0 on incomplete
  155.  * buffer, or 1 on success. On success, the subpic will be in pic; on error, pic
  156.  * may have a bitmap allocated ( != NULL), and should be freed.
  157.  *
  158.  * buf is the actual buffer; bufsiz is its length.
  159.  * tm is the time, in ms, of this packet, from the start of the stream; used for
  160.  * computing start and stop times. */
  161.  
  162. static int do_subpic_decode(const unsigned char *buf, size_t bufsiz, int tm,
  163.                             class subpic_t *pic)
  164. {
  165.     unsigned dataLen;
  166.     
  167.     if(bufsiz < 4) return -1; /* way too short */
  168.     /* grab the length of the data packet */
  169.     dataLen = (buf[2] << 8) + buf[3];
  170.  
  171.     if(dataLen > bufsiz) return 0; /* incomplete */
  172.  
  173.     /* set default values */
  174.     pic->x = pic->y = pic->sX =  pic->sY = -1; /* required values */
  175.     pic->start = pic->stop = -1;
  176.  
  177.     /* parse the control packet */
  178.     unsigned offset[2];
  179.     bool control_done = false;
  180.     unsigned i = dataLen;
  181.  
  182.     /* for dupe offset checking */
  183.     unsigned offsets_done[255];
  184.     int offsets_done_n = 0;
  185.  
  186.     while(!control_done) {
  187.             unsigned start = i; /* offset of this sequence */
  188.             
  189.             /* decode each sequence of the control block */
  190.             bool control_sequence_done = false;
  191.  
  192.             if(i+4 >= bufsiz) return -1;
  193.  
  194.             int seq_time = 0;            
  195.             seq_time += buf[i++] << 8;
  196.             seq_time += buf[i++];
  197.  
  198. #define SUB_PRECISION 88.0
  199.             /* subpic timing is in 1/SUB_PRECISION of a second; convert to
  200.              * ms */
  201.  
  202.             seq_time = (int) (((double)seq_time / SUB_PRECISION) * 1000.0);
  203.  
  204.             /* convert PTS to it's in 1/SUB_PRECISION of a second; we want references to
  205.              * the 27Mhz MPEG2 reference clock */
  206.             // seq_time *= 27000;
  207.  
  208.             unsigned next = 0; /* offset to the next sequence, or to this one if last */
  209.             next += buf[i++] << 8;
  210.             next += buf[i++];
  211.             if(next > bufsiz) return 0; /* incomplete */
  212.  
  213.             /* if it's the same as this, then this is the last */
  214.             if(next == start) control_done = true;
  215.             
  216.             /* if next is in the data packet, we have a problem */
  217.             if(next < dataLen) {
  218.                 _RPT2(0, "Invalid next %u (dataLen %u)\n", next, dataLen);
  219.                 return -1;
  220.             }
  221.  
  222.             /* make sure we're not looping */
  223.             for(int n = 0; n < offsets_done_n; n++) {
  224.                 if(offsets_done[n] == start) {
  225.                     /* oops */
  226.                     _RPT1(0, "next %u encountered twice; looping\n", next);
  227.                     return -1;
  228.                 }
  229.             }
  230.             /* add after the check: it's OK to receive the *current* start as
  231.              * the next (it indicates last packet) */
  232.             offsets_done[offsets_done_n++] = start;
  233.             
  234.             while(!control_sequence_done) {
  235.                 unsigned char c;
  236.                 if(i >= bufsiz) return -1;
  237.                 c = buf[i++];
  238.                 bool aligned = true;
  239.  
  240.                 switch(c) {
  241.                 case 1: /* start time */
  242.                     pic->start = seq_time + tm;
  243.                     _RPT1(0, "Subpic starts on %x\n", pic->start);
  244.                     break;
  245.  
  246.                 case 2: /* stop time */
  247.                     pic->stop = seq_time + tm;
  248.                     break;
  249.  
  250.                 case 3: {
  251.                     /* palette */
  252.                     if(i+1 >= bufsiz) return -1;
  253.                     for(int p = 3; p >= 0; p--) {
  254.                         pic->colors[p] = grab_nibble(buf, i, aligned);
  255.                     }    
  256.                     
  257.                     break;
  258.                 }
  259.                 case 4: {
  260.                     /* transparency palette (?) */
  261.                     if(i+1 >= bufsiz) return -1;
  262.  
  263.                     /* we want 8 bit alpha, not 4, for future features */
  264.                     for(int p = 3; p >= 0; p--) {                        
  265.                         pic->alpha[p] = (int) (((double)grab_nibble(buf, i, aligned) / 15.0) * 255);
  266.                     }
  267.  
  268.                     break;
  269.                 }
  270.                 case 5: /* image coordinates */
  271.                     /* width */
  272.                     int endX, endY;
  273.                     if(i+5 >= bufsiz) return -1;
  274.     
  275.                     pic->sX = (grab_nibble(buf, i, aligned) << 8) + 
  276.                               (grab_nibble(buf, i, aligned) << 4) +
  277.                               grab_nibble(buf, i, aligned);
  278.  
  279.                     endX = (grab_nibble(buf, i, aligned) << 8) + 
  280.                            (grab_nibble(buf, i, aligned) << 4) +
  281.                               grab_nibble(buf, i, aligned);
  282.  
  283.                     pic->sY = (grab_nibble(buf, i, aligned) << 8) + 
  284.                               (grab_nibble(buf, i, aligned) << 4) +
  285.                               grab_nibble(buf, i, aligned);
  286.                     
  287.                     endY = (grab_nibble(buf, i, aligned) << 8) + 
  288.                            (grab_nibble(buf, i, aligned) << 4) +
  289.                               grab_nibble(buf, i, aligned);
  290.     
  291.                     pic->x = 1 + endX - pic->sX;
  292.                     pic->y = 1 + endY - pic->sY;
  293.     
  294.                     break;
  295.                 case 0x06: /* image 1 / image 2 offsets */
  296.                     if(i+1 >= bufsiz) return -1;
  297.                     offset[0] = ((unsigned int)buf[i++]) << 8;
  298.                     offset[0] += buf[i++];
  299.                     offset[1] = ((unsigned int)buf[i++]) << 8;
  300.                     offset[1] += buf[i++];
  301.                     break;
  302.                 case 0x07: /* unknown; appears to be 3 bytes */
  303.                     if(i+2 >= bufsiz) return -1;
  304.                     i += 3;
  305.                     break;
  306.     
  307.                 case 0xff: /* end of sequence */                    
  308.                     control_sequence_done = true;
  309.                     break;
  310.  
  311.                 default:
  312.                     /* we can't continue parsing past unknown commands
  313.                      * because we need their length.  we can try to display
  314.                      * them anyway, hoping we already have sufficient data--
  315.                      * if we don't, we'll bail anyway.  at least in my test DVDs,
  316.                      * control sequences appear generally sorted numerically, so
  317.                      * unless we hit c == 0 somehow, we might be OK */
  318.                     _RPT1(0, "Unknown subpic command: %2.2x\n", c);
  319.                     control_done = control_sequence_done = true;
  320.                 }
  321.             }
  322.             i = next;    
  323.     }
  324.  
  325.     /* sanity */
  326.     if(pic->x == -1 || pic->y == -1 || pic->sX == -1 || pic->sY == -1 ||
  327.         pic->start == -1 || pic->stop == -1) {
  328.         /* some required piece of data is missing */
  329.         _RPT0(0, "subpic data missing\n");
  330.         return -1;
  331.     }
  332.  
  333.     /* now we can alloc the bitmap */
  334.     pic->bitmap = new unsigned char[pic->x * pic->y];
  335.     memset(pic->bitmap, 0, pic->x * pic->y);
  336.  
  337.     int x = 0, y = 0;
  338.     /* note: all Y wrapping is done in twos, since the pic is interlaced.
  339.      * do even.scanlines first, then odd
  340.      */
  341.     
  342.     int state = 0;
  343.     bool aligned = true;
  344.     if(offset[0] >= bufsiz) return -1;
  345.     if(offset[1] >= bufsiz) return -1;
  346.  
  347.     i = offset[state];
  348.     while(1) {
  349.         unsigned short val;
  350.  
  351.         do{
  352.             if(i >= bufsiz) return -1;
  353.             val = grab_nibble(buf, i, aligned);
  354.             if(val >= 0x004) break;    /* one-byte */
  355.  
  356.             if(i >= bufsiz) return -1;
  357.             val = (val << 4) + grab_nibble(buf, i, aligned);
  358.             if(val >= 0x010) break;    /* two-byte, 1x .. 3x */
  359.  
  360.             if(i >= bufsiz) return -1;
  361.             val = (val << 4) + grab_nibble(buf, i, aligned);
  362.             if(val >= 0x040) break; /* three-byte, 04x .. 0fx */
  363.             
  364.             if(i >= bufsiz) return -1;
  365.             val = (val << 4) + grab_nibble(buf, i, aligned);
  366.             if(val >= 0x100) break; /* four-byte, 01xx .. 03xx */
  367.             /* four-byte, 00xx */
  368.       
  369.       /* if we are here, we have to run till the end of the line
  370.          with the color in the low nibble of val. Setup val accordingly */
  371.       val &= 3;
  372.       val |= ((pic->x - x)<<2);
  373.  
  374.         } while(0);
  375.         int pixNum = val >> 2;
  376.         int color = val & 3;
  377.         if(pixNum == 0) pixNum = pic->x - x; /* line feed */
  378.         if(pixNum + x > pic->x)
  379.             pixNum = pic->x - x; /* shouldn't happen: cap pixNum */
  380.             
  381.         while(pixNum--) {
  382.             pic->bitmap[y * pic->x + x] = color;
  383.             x++;
  384.             if(x == pic->x) {
  385.                 /* wrap */
  386.                 x = 0;
  387.                 y += 2;
  388.                 if(y > pic->y) break;
  389.                 if(!aligned) {
  390.                     if(i >= bufsiz) return -1;
  391.                     grab_nibble(buf, i, aligned);
  392.                 }
  393.             }
  394.         }
  395.         if(y >= pic->y) {
  396.             /* hit the bottom */
  397.             state++;
  398.             if(state == 2) break; /* done */
  399.             /* finished even; do odd */
  400.             y = 1;
  401.             i = offset[state];
  402.         }
  403.     }
  404.  
  405.     return 1;
  406. }
  407.  
  408. /* subpics often have lots of unused blank space on the borders.
  409.  * remove it. */
  410. static void subpic_squeeze(class subpic_t *s)
  411. {
  412.     int newX = 0, newY = 0,
  413.         newSX = s->sX, newSY = s->sY; /* newX and newY is the new size; newSX and newSY
  414.                                        * are the offsets from the top and left of the old
  415.                                        * image */
  416.     bool nontrans = false;
  417.     int x, y;
  418.     for(y = 0; y < s->y; y++) {
  419.         for(x = 0; x < s->x; x++) {
  420.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  421.             if(s->alpha[pcolor] != 0x0) {
  422.                 nontrans = true;
  423.                 break;
  424.             }
  425.         }
  426.         if(nontrans) break;
  427.     }
  428.     newSY = y;
  429.  
  430.     /* bottom */
  431.     nontrans = false;
  432.     for(y = s->y-1; y >= newSY; y--) {
  433.         for(x = 0; x < s->x; x++) {
  434.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  435.             if(s->alpha[pcolor] != 0x0) {
  436.                 nontrans = true;
  437.                 break;
  438.             }
  439.         }
  440.         if(nontrans) break;
  441.     }
  442.     newY = y - newSY + 1;
  443.     
  444.     /* left */
  445.     nontrans = false;
  446.     for(x = 0; x < s->x; x++) {
  447.         for(y = 0; y < s->y; y++) {
  448.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  449.             if(s->alpha[pcolor] != 0x0) {
  450.                 nontrans = true;
  451.                 break;
  452.             }
  453.         }
  454.         if(nontrans) break;
  455.     }
  456.  
  457.     newSX = x;
  458.  
  459.     /* right */
  460.     nontrans = false;
  461.     for(x = s->x-1; x > newSX; x--) {
  462.         for(y = 0; y < s->y; y++) {
  463.             int pcolor = s->bitmap[y*s->x + x]; /* subpic palette index (0-3) */
  464.             if(s->alpha[pcolor] != 0x0) {
  465.                 nontrans = true;
  466.                 break;
  467.             }
  468.         }
  469.         if(nontrans) break;
  470.     }
  471.     newX = x - newSX + 1;
  472.  
  473.     /* make sure the pixel count is even */
  474.     if(newX==s->x) newX = newX%2 ? newX-1 : newX;
  475.     if(newY==s->y) newY = newY%2 ? newY-1 : newY;
  476.  
  477.     newX = newX%2 ? newX+1 : newX;
  478.     newY = newY%2 ? newY+1 : newY;
  479.  
  480.     /* recons new image */
  481.   /* This stuff is deleted in subpic_free() */
  482.     TYUVImage yuv;
  483.     s->frRecons = new CFrame;
  484.     s->frRecons->Set( newX, newY, FRAME_YUV444A );
  485.  
  486.     s->frRecons->GetYuvInfo( &yuv );
  487.  
  488.  
  489.     unsigned char *yu = yuv.y;
  490.     unsigned char *u = yuv.u;
  491.     unsigned char *v = yuv.v;
  492.   unsigned char *a = yuv.a;
  493.  
  494.     for(int j = 0; j < newY; j++) {
  495.         for(int i = 0; i < newX; i++) {
  496.             int pcolor = s->bitmap[(newSY+j)*s->x+(newSX+i)];
  497.  
  498.             *a++ = s->alpha[pcolor];
  499.         
  500.             pcolor = s->colors[pcolor]; /* convert subpic palette index into master palette */            
  501.   
  502.       *yu++ = palette[pcolor][1] ;
  503.       *u++ = palette[pcolor][2] ;
  504.       *v++ = palette[pcolor][3];
  505.         }
  506.     }
  507.  
  508.     s->x = newX;
  509.     s->y = newY;
  510.     s->sX += newSX;
  511.     s->sY += newSY;
  512.  
  513.     delete []s->bitmap;
  514.     s->bitmap = NULL;
  515. }
  516.  
  517. static unsigned char subPicBuf[64000];
  518. static int subPicLen = 0;
  519.  
  520. int subpic_decode(const unsigned char *buf, size_t bufsiz, int tm)
  521. {
  522.     class subpic_t *pic = new class subpic_t;
  523.     static int start_time = 0;
  524.  
  525.     pic->bitmap = NULL;
  526.  
  527.     if(subPicLen + bufsiz >= 64000) {
  528.         /* overflow */
  529.         bufsiz = 0;
  530.         return -1;
  531.     }
  532.  
  533.     if(!start_time && !tm) {
  534.         /* this isn't a start packet, and we don't have one yet; it's
  535.          * mid-packet.  discard it. */
  536.         return -1;
  537.     }
  538.  
  539.     if(tm)
  540.     {
  541.         start_time=tm;
  542.         subPicLen = 0;
  543.     }
  544.     _RPT1(0, "? Subpic starts on %x\n", tm);
  545.     memmove(subPicBuf+subPicLen, buf, bufsiz);
  546.     subPicLen += bufsiz;
  547.  
  548.     int ret = do_subpic_decode(subPicBuf, subPicLen, start_time, pic);
  549.  
  550.     if(ret == -1 || ret > 0) {
  551.         if(ret == -1)
  552.             int z = 1; /* debug breakpoint target */
  553.         subPicLen = 0; /* error or success; clear the buffer */
  554.     }
  555.     if(ret <= 0) {
  556.         /* error or incomplete */
  557.         delete pic;
  558.  
  559.         return ret;
  560.     }
  561.  
  562.     /* success; store it */
  563.     start_time = 0;
  564.     subpic_squeeze(pic);
  565.  
  566.     pic->next = pics;
  567.     pic->prev = NULL;
  568.     if(pic->next) pic->next->prev = pic;
  569.  
  570.     pics = pic;
  571.  
  572.     return ret;
  573. }
  574.  
  575.