Ticket #8594: encode_dxa.patch

File encode_dxa.patch, 21.7 KB (added by johndoe123, 17 years ago)

The patch file

  • encode_dxa.cpp

     
    4141
    4242static CompressMode gCompMode = kMP3Mode;
    4343
     44enum ScaleMode { S_NONE, S_INTERLACED, S_DOUBLE };
     45
     46struct DiffStruct {
     47        unsigned short map;
     48        int count;
     49        byte pixels[BLOCKW*BLOCKH];
     50};
     51
    4452class DxaEncoder {
    4553private:
    4654        FILE *_dxa;
    47         int _width, _height, _framerate, _framecount;
     55        int _width, _height, _framerate, _framecount, _workheight;
    4856        uint8 *_prevframe, *_prevpalette;
     57        ScaleMode _scaleMode;
    4958
    50         bool m12blocksAreEqual(byte *frame, int x, int y, int x2, int y2);
    51         bool m12blockIsSolidColor(byte *frame, int x, int y, byte &color);
    52         void m12blockDelta(byte *frame, int x, int y, unsigned short &diffMap, int &diffCount, byte diffPix[]);
    53         bool m12motionVector(byte *frame, int x, int y, int &mx, int &my);
    54         uLong m12encode(byte *frame, byte *outbuf);
     59        byte *_codeBuf, *_dataBuf, *_motBuf, *_maskBuf;
     60    void grabBlock(byte *frame, int x, int y, int blockw, int blockh, byte *block);
     61    bool m13blocksAreEqual(byte *frame, int x, int y, int x2, int y2, int w, int h);
     62    bool m13blockIsSolidColor(byte *frame, int x, int y, int w, int h, byte &color);
     63    void m13blockDelta(byte *frame, int x, int y, int x2, int y2, DiffStruct &diff);
     64    bool m13motionVector(byte *frame, int x, int y, int w, int h, int &mx, int &my);
     65    int m13countColors(byte *block, byte *pixels, unsigned long &code, int &codeSize);
     66    uLong m13encode(byte *frame, byte *outbuf);
    5567
    5668public:
    57         DxaEncoder(char *filename, int width, int height, int fps);
     69        DxaEncoder(char *filename, int width, int height, int framerate, ScaleMode scaleMode);
    5870        ~DxaEncoder();
    5971        void writeHeader();
    6072        void writeNULL();
    6173        void writeFrame(uint8 *frame, uint8 *palette);
    6274};
    6375
    64 DxaEncoder::DxaEncoder(char *filename, int width, int height, int framerate) {
     76DxaEncoder::DxaEncoder(char *filename, int width, int height, int framerate, ScaleMode scaleMode) {
    6577        _dxa = fopen(filename, "wb");
    6678        _width = width;
    6779        _height = height;
     
    6981        _framecount = 0;
    7082        _prevframe = new uint8[_width * _height];
    7183        _prevpalette = new uint8[768];
     84        _scaleMode = scaleMode;
     85    _workheight = _scaleMode == S_NONE ? _height : _height / 2;
    7286
     87        _codeBuf = new byte[_width * _height / 16];
     88    _dataBuf = new byte[_width * _height];
     89    _motBuf = new byte[_width * _height];
     90    _maskBuf = new byte[_width * _height];
     91
    7392        writeHeader();
    7493}
    7594
     
    8099
    81100        fclose(_dxa);
    82101
     102        delete[] _codeBuf;
     103    delete[] _dataBuf;
     104    delete[] _motBuf;
     105    delete[] _maskBuf;
     106
    83107        delete[] _prevframe;
    84108        delete[] _prevpalette;
    85109}
     
    88112        //DEXA
    89113        uint8 version = 0;
    90114
     115    /* remember the scaling mode */
     116    if (_scaleMode == S_INTERLACED)
     117        version |= 0x80;
     118    else if (_scaleMode == S_DOUBLE)
     119        version |= 0x40;
     120
    91121        writeUint32LE(_dxa, typeDEXA);
    92122        writeByte(_dxa, version);
    93123
     
    102132        writeUint32LE(_dxa, typeNULL);
    103133}
    104134
    105 void DxaEncoder::writeFrame(uint8 *frame, uint8 *palette) {
     135void DxaEncoder::writeFrame(byte *frame, byte *palette) {
     136
    106137        if (_framecount == 0 || memcmp(_prevpalette, palette, 768)) {
    107138                writeUint32LE(_dxa, typeCMAP);
    108139                fwrite(palette, 768, 1, _dxa);
    109 
    110140                memcpy(_prevpalette, palette, 768);
    111141        } else {
    112142                writeNULL();
    113143        }
    114144
    115         if (_framecount == 0 || memcmp(_prevframe, frame, _width * _height)) {
     145        if (_framecount == 0 || memcmp(_prevframe, frame, _width * _workheight)) {
    116146                //FRAM
    117                 uint8 compType;
     147                byte compType;
    118148
    119149                writeUint32LE(_dxa, typeFRAM);
    120150
    121151                if (_framecount == 0)
    122152                        compType = 2;
    123153                else
    124                         //compType = 3;
    125                         compType = 12;
     154                        compType = 13;
    126155
    127156                switch (compType) {
     157
    128158                case 2:
    129159                        {
    130                                 uLong outsize = _width * _height;
    131                                 uint8 *outbuf = new uint8[outsize];
    132 
    133                                 compress2(outbuf, &outsize, frame, _width * _height, 9);
    134 
     160                                uLong outsize = _width * _workheight;
     161                                byte *outbuf = new byte[outsize];
     162                                compress2(outbuf, &outsize, frame, _width * _workheight, 9);
    135163                                writeByte(_dxa, compType);
    136 
    137164                                writeUint32BE(_dxa, outsize);
    138 
    139165                                fwrite(outbuf, outsize, 1, _dxa);
    140 
    141166                                delete[] outbuf;
    142 
    143167                                break;
    144168                        }
    145                 case 3:
    146                         {
    147                                 uLong outsize1 = _width * _height;
    148                                 uLong outsize2 = outsize1;
    149                                 uLong outsize;
    150                                 uint8 *outbuf;
    151                                 uint8 *outbuf1 = new uint8[outsize1];
    152                                 uint8 *outbuf2 = new uint8[outsize2];
    153                                 uint8 *xorbuf = new uint8[_width * _height];
    154169
    155                                 for (int i = 0; i < _width * _height; i++)
    156                                         xorbuf[i] = _prevframe[i] ^ frame[i];
     170        case 13:
    157171
    158                                 compress2(outbuf1, &outsize1, xorbuf, _width * _height, 9);
    159                                 compress2(outbuf2, &outsize2, frame, _width * _height, 9);
     172            {
    160173
    161                                 if (outsize1 < outsize2) {
    162                                         compType = 3;
    163                                         outsize = outsize1;
    164                                         outbuf = outbuf1;
    165                                 } else {
    166                                         compType = 2;
    167                                         outsize = outsize2;
    168                                         outbuf = outbuf2;
    169                                 }
     174                int r;
    170175
    171                                 writeByte(_dxa, compType);
     176                                uLong frameoutsize;
     177                                byte *frameoutbuf;
    172178
    173                                 writeUint32BE(_dxa, outsize);
     179                                byte *xorbuf = new byte[_width * _workheight];
     180                                uLong xorsize_z = _width * _workheight;
     181                                byte *xorbuf_z = new byte[xorsize_z];
    174182
    175                                 fwrite(outbuf, outsize, 1, _dxa);
     183                                uLong rawsize_z = _width * _workheight;
     184                                byte *rawbuf_z = new byte[rawsize_z];
    176185
    177                                 delete[] outbuf1;
    178                                 delete[] outbuf2;
    179                                 delete[] xorbuf;
     186                                uLong m13size = _width * _workheight * 2;
     187                                byte *m13buf = new byte[m13size];
     188                                uLong m13size_z = _width * _workheight;
     189                                byte *m13buf_z = new byte[m13size_z];
    180190
    181                                 break;
    182                         }
    183                 case 12:
     191                /* encode the delta frame with mode 12 */
     192                                m13size = m13encode(frame, m13buf);
    184193
    185                         {
     194                /* create the xor buffer */
     195                                for (int i = 0; i < _width * _workheight; i++)
     196                                        xorbuf[i] = _prevframe[i] ^ frame[i];
    186197
    187                                 uLong outsize1 = _width * _height;
    188                                 uLong outsize2 = outsize1;
    189                                 uLong outsize3 = outsize1*2;
    190                                 uLong outsize4 = outsize1;
    191                                 uLong outsize;
    192                                 uint8 *outbuf;
    193                                 uint8 *outbuf1 = new uint8[outsize1];
    194                                 uint8 *outbuf2 = new uint8[outsize2];
    195                                 uint8 *outbuf3 = new uint8[outsize3];
    196                                 uint8 *outbuf4 = new uint8[outsize4];
    197                                 uint8 *xorbuf = new uint8[_width * _height];
     198                                /* compress the m13 buffer */
     199                                compress2(m13buf_z, &m13size_z, m13buf, m13size, 9);
    198200
    199                                 for (int i = 0; i < _width * _height; i++)
    200                                         xorbuf[i] = _prevframe[i] ^ frame[i];
     201                /* compress the xor buffer */
     202                                xorsize_z = m13size_z;
     203                                r = compress2(xorbuf_z, &xorsize_z, xorbuf, _width * _workheight, 9);
     204                                if (r != Z_OK) xorsize_z = 0xFFFFFFF;
    201205
    202                                 compress2(outbuf1, &outsize1, xorbuf, _width * _height, 9);
    203                                 compress2(outbuf2, &outsize2, frame, _width * _height, 9);
    204                                 if (outsize1 < outsize2) {
     206                                if (m13size_z < xorsize_z) {
     207                                        compType = 13;
     208                                        frameoutsize = m13size_z;
     209                                        frameoutbuf = m13buf_z;
     210                                } else {
    205211                                        compType = 3;
    206                                         outsize = outsize1;
    207                                         outbuf = outbuf1;
    208                                 } else {
    209                                         compType = 2;
    210                                         outsize = outsize2;
    211                                         outbuf = outbuf2;
     212                                        frameoutsize = xorsize_z;
     213                                        frameoutbuf = xorbuf_z;
    212214                                }
    213215
    214                                 outsize3 = m12encode(frame, outbuf3);
     216                /* compress the raw frame */
     217                                rawsize_z = frameoutsize;
     218                                r = compress2(rawbuf_z, &rawsize_z, frame, _width * _workheight, 9);
     219                                if (r != Z_OK) rawsize_z = 0xFFFFFFF;
    215220
    216                                 compress2(outbuf4, &outsize4, outbuf3, outsize3, 9);
     221                                if (rawsize_z < frameoutsize) {
     222                                        compType = 2;
     223                                        frameoutsize = rawsize_z;
     224                                        frameoutbuf = rawbuf_z;
     225                    }
    217226
    218                                 if (outsize4 < outsize) {
    219                                         compType = 12;
    220                                         outsize = outsize4;
    221                                         outbuf = outbuf4;
    222                                 }
    223 
    224227                                writeByte(_dxa, compType);
    225                                 writeUint32BE(_dxa, outsize);
    226                                 fwrite(outbuf, outsize, 1, _dxa);
     228                                writeUint32BE(_dxa, frameoutsize);
     229                                fwrite(frameoutbuf, frameoutsize, 1, _dxa);
    227230
    228                                 delete[] outbuf1;
    229                                 delete[] outbuf2;
    230                                 delete[] outbuf3;
    231                                 delete[] outbuf4;
     231                                delete[] xorbuf_z;
     232                                delete[] rawbuf_z;
     233                                delete[] m13buf_z;
     234                                delete[] m13buf;
    232235                                delete[] xorbuf;
    233236
    234237                                break;
    235238                        }
    236239                }
    237240
    238                 memcpy(_prevframe, frame, _width * _height);
     241                memcpy(_prevframe, frame, _width * _workheight);
    239242
    240243        } else {
    241244                writeNULL();
     
    244247        _framecount++;
    245248}
    246249
    247 bool DxaEncoder::m12blocksAreEqual(byte *frame, int x, int y, int x2, int y2) {
     250bool DxaEncoder::m13blocksAreEqual(byte *frame, int x, int y, int x2, int y2, int w, int h) {
    248251        byte *b1 = _prevframe + x + y * _width;
    249252        byte *b2 = frame + x2 + y2 * _width;
    250         for (int yc = 0; yc < BLOCKH; yc++) {
    251                 if (memcmp(b1, b2, BLOCKW))
     253        for (int yc = 0; yc < h; yc++) {
     254                if (memcmp(b1, b2, w))
    252255                        return false;
    253256                b1 += _width;
    254257                b2 += _width;
     
    256259        return true;
    257260}
    258261
    259 bool DxaEncoder::m12blockIsSolidColor(byte *frame, int x, int y, byte &color) {
     262bool DxaEncoder::m13blockIsSolidColor(byte *frame, int x, int y, int w, int h, byte &color) {
    260263        byte *b2 = frame + x + y * _width;
    261264        color = *b2;
    262         for (int yc = 0; yc < BLOCKH; yc++) {
    263                 for (int xc = 0; xc < BLOCKW; xc++) {
     265        for (int yc = 0; yc < h; yc++) {
     266                for (int xc = 0; xc < w; xc++) {
    264267                        if (b2[xc] != color)
    265268                                return false;
    266269                }
     
    269272        return true;
    270273}
    271274
    272 void DxaEncoder::m12blockDelta(byte *frame, int x, int y, unsigned short &diffMap, int &diffCount, byte diffPix[]) {
     275void DxaEncoder::m13blockDelta(byte *frame, int x, int y, int x2, int y2, DiffStruct &diff) {
    273276        byte *b1 = _prevframe + x + y * _width;
    274         byte *b2 = frame + x + y * _width;
    275         diffCount = 0;
    276         diffMap = 0;
     277        byte *b2 = frame + x2 + y2 * _width;
     278        diff.count = 0;
     279        diff.map = 0;
    277280        for (int yc = 0; yc < BLOCKH; yc++) {
    278281                for (int xc = 0; xc < BLOCKW; xc++) {
    279282                        if (b1[xc] != b2[xc]) {
    280                                 diffMap = (diffMap << 1) | 1;
    281                                 diffPix[diffCount++] = b2[xc];
     283                                diff.map = (diff.map << 1) | 1;
     284                                diff.pixels[diff.count++] = b2[xc];
    282285                        } else {
    283                                 diffMap = (diffMap << 1) | 0;
     286                                diff.map = (diff.map << 1) | 0;
    284287                        }
    285288                }
    286289                b1 += _width;
     
    288291        }
    289292}
    290293
    291 bool DxaEncoder::m12motionVector(byte *frame, int x, int y, int &mx, int &my) {
     294bool DxaEncoder::m13motionVector(byte *frame, int x, int y, int w, int h, int &mx, int &my) {
    292295        int xmin = (0 > x-7) ? 0 : x-7;
    293296        int ymin = (0 > y-7) ? 0 : y-7;
    294297        int xmax = (_width < x+8) ? _width : x+8;
    295         int ymax = (_height < y+8) ? _height : y+8;
     298        int ymax = (_workheight < y+8) ? _height : y+8;
    296299        for (int yc = ymin; yc < ymax; yc++) {
    297300                for (int xc = xmin; xc < xmax; xc++) {
    298                         if (m12blocksAreEqual(frame, xc, yc, x, y)) {
    299                                 mx = xc - x;
    300                                 my = yc - y;
     301                        if (m13blocksAreEqual(frame, xc, yc, x, y, w, h)) {
     302                        mx = xc - x;
     303                        my = yc - y;
    301304                                return true;
    302305                        }
    303306                }
     
    305308        return false;
    306309}
    307310
    308 uLong DxaEncoder::m12encode(byte *frame, byte *outbuf) {
     311int DxaEncoder::m13countColors(byte *block, byte *pixels, unsigned long &code, int &codeSize) {
     312
     313    code = 0;
     314    codeSize = 0;
     315
     316    /* count the number of colors used in this block */
     317    int count = 0;
     318    int colTab[256];
     319    for (int i = 0; i < 256; i++)
     320        colTab[i] = -1;
     321    for (int i = 0; i < BLOCKW * BLOCKH; i++) {
     322        if (colTab[block[i]] == -1) {
     323            colTab[block[i]] = count;
     324            pixels[count] = block[i];
     325            count++;
     326        }
     327    }
     328
     329    if (count <= 4) {
     330        /* set the bitmask */
     331        if (count == 2) {
     332            for (int i = 15; i >= 0; i--) {
     333                code = (code << 1) | colTab[block[i]];
     334            }
     335            codeSize = 2;
     336        } else if (count == 4 || count == 3) {
     337            for (int i = 15; i >= 0; i--) {
     338                code = (code << 2) | colTab[block[i]];
     339            }
     340            codeSize = 4;
     341        }
     342    }
     343
     344    return count;
     345
     346}
     347
     348/* grab the block */
     349void DxaEncoder::grabBlock(byte *frame, int x, int y, int blockw, int blockh, byte *block) {
     350    byte *b2 = (byte*)frame + x + y * _width;
     351    for (int yc = 0; yc < blockh; yc++) {
     352        memcpy(&block[yc*blockw], b2, blockw);
     353        b2 += _width;
     354    }
     355}
     356
     357uLong DxaEncoder::m13encode(byte *frame, byte *outbuf) {
     358
     359        byte *codeB = _codeBuf;
     360    byte *dataB = _dataBuf;
     361    byte *motB = _motBuf;
     362    byte *maskB = _maskBuf;
     363
    309364        byte *outb = outbuf;
    310365        byte color;
    311366        int mx, my;
    312         unsigned short diffMap;
    313         int diffCount;
    314         byte diffPix[BLOCKW*BLOCKH];
     367        DiffStruct diff;
    315368
    316         for (int by = 0; by < _height; by += BLOCKH) {
     369        memset(_codeBuf, 0, _width * _height / 16);
     370    memset(_dataBuf, 0, _width * _height);
     371    memset(_motBuf, 0, _width * _height);
     372    memset(_maskBuf, 0, _width * _height);
     373
     374        for (int by = 0; by < _workheight; by += BLOCKH) {
    317375                for (int bx = 0; bx < _width; bx += BLOCKW) {
    318                         if (m12blocksAreEqual(frame, bx, by, bx, by)) {
    319                                 *outb++ = 0;
    320                                 continue;
    321                         }
    322376
    323                         if (m12blockIsSolidColor(frame, bx, by, color)) {
    324                                 *outb++ = 2;
    325                                 *outb++ = color;
     377            if (m13blocksAreEqual(frame, bx, by, bx, by, BLOCKW, BLOCKH)) {
     378                                *codeB++ = 0;
    326379                                continue;
    327                         }
     380            }
    328381
    329                         if (m12motionVector(frame, bx, by, mx, my)) {
    330                                 byte mbyte = 0;
    331                                 if (mx < 0) mbyte |= 0x80;
    332                                 mbyte |= (abs(mx) & 7) << 4;
    333                                 if (my < 0) mbyte |= 0x08;
    334                                 mbyte |= abs(my) & 7;
    335                                 *outb++ = 4;
    336                                 *outb++ = mbyte;
     382                        if (m13blockIsSolidColor(frame, bx, by, BLOCKW, BLOCKH, color)) {
     383                                *codeB++ = 2;
     384                                *dataB++ = color;
    337385                                continue;
    338386                        }
    339387
    340                         m12blockDelta(frame, bx, by, diffMap, diffCount, diffPix);
     388            if (m13motionVector(frame, bx, by, BLOCKW, BLOCKH, mx, my)) {
     389                /* motion vector */
     390                            byte motionByte = 0;
     391                            if (mx < 0) motionByte |= 0x80;
     392                            motionByte |= (abs(mx) & 7) << 4;
     393                            if (my < 0) motionByte |= 0x08;
     394                            motionByte |= abs(my) & 7;
     395                            *codeB++ = 4;
     396                            *motB++ = motionByte;
     397                            continue;
     398            }
    341399
    342                         if (diffCount >= 14) {
    343                                 // in this case we store all 16 pixels
    344                                 *outb++ = 3;
    345                                 byte *b2 = (byte*)frame + bx + by * _width;
    346                                 for (int yc = 0; yc < BLOCKH; yc++) {
    347                                         memcpy(outb, b2, BLOCKW);
    348                                         b2 += _width;
    349                                         outb += BLOCKW;
    350                                 }
    351                                 continue;
    352                         } else {
    353                                 static const struct { uint16 mask; uint8 sh1, sh2; } maskTbl[6] = {
    354                                         {0xFF00, 0, 0},
    355                                         {0x0FF0, 8, 0},
    356                                         {0x00FF, 8, 8},
    357                                         {0x0F0F, 8, 4},
    358                                         {0xF0F0, 4, 0},
    359                                         {0xF00F, 4, 4}
    360                                 };
     400            byte subMask = 0;
     401            byte subMot[4], subData[16];
     402            int subMotSize = 0, subDataSize = 0;
    361403
    362                                 bool smallMask = false;
     404            {
    363405
    364                                 // here we check if the difference bitmap can be stored in only one byte
    365                                 for (int m = 0; m < 6; m++) {
    366                                         if ((diffMap & maskTbl[m].mask) == 0) {
    367                                                 smallMask = true;
    368                                                 *outb++ = 10 + m;
    369                                                 *outb++ = ((diffMap >> maskTbl[m].sh1) & 0xF0) | ((diffMap >> maskTbl[m].sh2) & 0x0F);
    370                                                 break;
    371                                         }
    372                                 }
     406                static const int subX[4] = {0, 2, 0, 2};
     407                static const int subY[4] = {0, 0, 2, 2};
    373408
    374                                 if (!smallMask) {
    375                                         *outb++ = 1;
    376                                         *(unsigned short*)outb = diffMap;
    377                                         outb += 2;
    378                                 }
     409                /* 0: skip
     410                   1: solid color (+ data byte)
     411                   2: motion vector (+ mot byte)
     412                   3: raw block (+ 4 data bytes)
     413                */
    379414
    380                                 memcpy(outb, diffPix, diffCount);
    381                                 outb += diffCount;
    382                                 continue;
    383                         }
     415                for (int subBlock = 0; subBlock < 4; subBlock++) {
     416
     417                    int sx = bx + subX[subBlock], sy = by + subY[subBlock];
     418                    byte scolor;
     419                    int smx, smy;
     420
     421                    if (m13blocksAreEqual(frame, sx, sy, sx, sy, BLOCKW/2, BLOCKH/2)) {
     422                        subMask = (subMask << 2) | 0;
     423                        continue;
     424                    }
     425
     426                    if (m13blockIsSolidColor(frame, sx, sy, BLOCKW/2, BLOCKH/2, scolor)) {
     427                        subData[subDataSize++] = scolor;
     428                        subMask = (subMask << 2) | 1;
     429                        continue;
     430                    }
     431
     432                    if (m13motionVector(frame, sx, sy, BLOCKW/2, BLOCKH/2, smx, smy)) {
     433                                    byte motionByte = 0;
     434                                    if (smx < 0) motionByte |= 0x80;
     435                                    motionByte |= (abs(smx) & 7) << 4;
     436                                    if (smy < 0) motionByte |= 0x08;
     437                                    motionByte |= abs(smy) & 7;
     438                                    subMot[subMotSize++] = motionByte;
     439                        subMask = (subMask << 2) | 2;
     440                        continue;
     441                    }
     442
     443                    byte *b2 = (byte*)frame + sx + sy * _width;
     444                    for (int yc = 0; yc < BLOCKH/2; yc++) {
     445                        memcpy(&subData[subDataSize], b2, BLOCKW/2);
     446                        subDataSize += BLOCKW/2;
     447                        b2 += _width;
     448                    }
     449
     450                    subMask = (subMask << 2) | 3;
     451
     452                }
     453
     454            }
     455
     456            int blockSize = 0;
     457
     458            m13blockDelta(frame, bx, by, bx, by, diff);
     459
     460            byte block[16];
     461            grabBlock(frame, bx, by, BLOCKW, BLOCKW, block);
     462
     463            unsigned long code;
     464            int codeSize;
     465            byte pixels[16];
     466            int count = m13countColors(block, pixels, code, codeSize);
     467
     468            int countColorsSize = 1000;
     469            if (count == 2)
     470              countColorsSize = 4; // 2 bytes mask, 2 pixels
     471            else if (count <= 4)
     472              countColorsSize = 4 + count; // 4 bytes mask, count pixels
     473
     474            if (countColorsSize < diff.count + 2) {
     475                blockSize = countColorsSize;
     476            } else {
     477                if (diff.count <= 12) {
     478                    blockSize = 2 + diff.count;
     479                } else {
     480                    blockSize = 16;
     481                }
     482            }
     483
     484            if (1 + subMotSize + subDataSize < blockSize) {
     485                /* store subblocks */
     486                *codeB++ = 8;
     487                *maskB++ = subMask;
     488                memcpy(dataB, subData, subDataSize);
     489                dataB += subDataSize;
     490                memcpy(motB, subMot, subMotSize);
     491                motB += subMotSize;
     492            } else {
     493                /* store full block */
     494                if (countColorsSize < diff.count + 2) {
     495                    /* write the pixel values */
     496                    *codeB++ = 30 + count;
     497                    memcpy(dataB, pixels, count);
     498                    dataB += count;
     499                    memcpy(maskB, &code, codeSize);
     500                    maskB += codeSize;
     501                } else {
     502                    if (diff.count <= 12) {
     503                        /* difference map */
     504                                    *codeB++ = 1;
     505                                    *(unsigned short*)maskB = diff.map;
     506                                maskB += 2;
     507                                memcpy(dataB, diff.pixels, diff.count);
     508                                dataB += diff.count;
     509                    } else {
     510                        /* write the whole block */
     511                        *codeB++ = 3;
     512                        memcpy(dataB, block, 16);
     513                        dataB += 16;
     514                    }
     515                }
     516            }
     517
    384518                }
    385519        }
    386520
     521    outb = outbuf;
     522
     523    int size;
     524
     525    size = dataB - _dataBuf;
     526    memcpy(outb, &size, 4);
     527    outb += 4;
     528    size = motB - _motBuf;
     529    memcpy(outb, &size, 4);
     530    outb += 4;
     531    size = maskB - _maskBuf;
     532    memcpy(outb, &size, 4);
     533    outb += 4;
     534
     535    /* this size is always constant throughout a DXA */
     536    memcpy(outb, _codeBuf, codeB - _codeBuf);
     537    outb += codeB - _codeBuf;
     538
     539    memcpy(outb, _dataBuf, dataB - _dataBuf);
     540    outb += dataB - _dataBuf;
     541
     542    memcpy(outb, _motBuf, motB - _motBuf);
     543    outb += motB - _motBuf;
     544
     545    memcpy(outb, _maskBuf, maskB - _maskBuf);
     546    outb += maskB - _maskBuf;
     547
    387548        return outb - outbuf;
    388549}
    389550
     
    469630        return 0;
    470631}
    471632
    472 void readVideoInfo(char *filename, int &width, int &height, int &framerate, int &frames) {
     633void readVideoInfo(char *filename, int &width, int &height, int &framerate, int &frames,
     634    ScaleMode &scaleMode) {
     635
    473636        FILE *smk = fopen(filename, "rb");
    474637        if (!smk) {
    475638                printf("readVideoInfo: Can't open file: %s\n", filename);
    476639                exit(-1);
    477640        }
    478641
     642    scaleMode = S_NONE;
     643
    479644        char buf[4];
    480645        fread(buf, 1, 4, smk);
    481646        if (!memcmp(buf, "BIK", 3)) {
     
    503668                // If the Y-interlaced or Y-doubled flag is set, the RAD Video Tools
    504669                // will have scaled the frames to twice their original height.
    505670
    506                 if ((flags & 0x02) || (flags & 0x04))
    507                         height *= 2;
     671        if (flags & 0x02)
     672            scaleMode = S_INTERLACED;
     673        else if (flags & 0x04)
     674            scaleMode = S_DOUBLE;
     675
     676        if (scaleMode != S_NONE)
     677                height *= 2;
     678
    508679        } else {
    509680                error("readVideoInfo: Unknown type");
    510681        }
     
    577748
    578749        char strbuf[512];
    579750        int width, height, framerate, frames;
     751        ScaleMode scaleMode;
    580752       
    581753        /* compression mode */
    582754        gCompMode = kMP3Mode;
     
    634806        }
    635807
    636808        // read some data from the Bink or Smacker file.
    637         readVideoInfo(filename, width, height, framerate, frames);
     809        readVideoInfo(filename, width, height, framerate, frames, scaleMode);
    638810
    639811        printf("Width = %d, Height = %d, Framerate = %d, Frames = %d\n",
    640812                   width, height, framerate, frames);
    641813
    642814        // create the encoder object
    643815        sprintf(strbuf, "%s.dxa", prefix);
    644         DxaEncoder dxe(strbuf, width, height, framerate);
     816        DxaEncoder dxe(strbuf, width, height, framerate, scaleMode);
    645817
    646818        // No sound block
    647819        dxe.writeNULL();
     
    671843                }
    672844
    673845                if (!r) {
    674                         dxe.writeFrame(image, palette);
     846            if (scaleMode != S_NONE) {
     847                byte *unscaledImage = new byte[width * height / 2];
     848                for (int y = 0; y < height; y += 2)
     849                    memcpy(&unscaledImage[(width*y)/2], &image[width*y], width);
     850                        dxe.writeFrame(unscaledImage, palette);
     851                delete[] unscaledImage;
     852            } else {
     853                        dxe.writeFrame(image, palette);
     854            }
    675855                }
    676856
    677857                if (image) delete[] image;
     
    692872       
    693873        return 0;
    694874}
    695 
    696