Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Microsoft RLE decoder
  3.  * Copyright (C) 2008 Konstantin Shishkov
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * MS RLE decoder based on decoder by Mike Melanson and my own for TSCC
  25.  * For more information about the MS RLE format, visit:
  26.  *   http://www.multimedia.cx/msrle.txt
  27.  */
  28.  
  29. #include "libavutil/intreadwrite.h"
  30. #include "avcodec.h"
  31. #include "msrledec.h"
  32.  
  33. static int msrle_decode_pal4(AVCodecContext *avctx, AVPicture *pic,
  34.                              GetByteContext *gb)
  35. {
  36.     unsigned char rle_code;
  37.     unsigned char extra_byte, odd_pixel;
  38.     unsigned char stream_byte;
  39.     unsigned int pixel_ptr = 0;
  40.     int row_dec = pic->linesize[0];
  41.     int row_ptr = (avctx->height - 1) * row_dec;
  42.     int frame_size = row_dec * avctx->height;
  43.     int i;
  44.  
  45.     while (row_ptr >= 0) {
  46.         if (bytestream2_get_bytes_left(gb) <= 0) {
  47.             av_log(avctx, AV_LOG_ERROR,
  48.                    "MS RLE: bytestream overrun, %d rows left\n",
  49.                    row_ptr);
  50.             return AVERROR_INVALIDDATA;
  51.         }
  52.         rle_code = stream_byte = bytestream2_get_byteu(gb);
  53.         if (rle_code == 0) {
  54.             /* fetch the next byte to see how to handle escape code */
  55.             stream_byte = bytestream2_get_byte(gb);
  56.             if (stream_byte == 0) {
  57.                 /* line is done, goto the next one */
  58.                 row_ptr -= row_dec;
  59.                 pixel_ptr = 0;
  60.             } else if (stream_byte == 1) {
  61.                 /* decode is done */
  62.                 return 0;
  63.             } else if (stream_byte == 2) {
  64.                 /* reposition frame decode coordinates */
  65.                 stream_byte = bytestream2_get_byte(gb);
  66.                 pixel_ptr += stream_byte;
  67.                 stream_byte = bytestream2_get_byte(gb);
  68.                 row_ptr -= stream_byte * row_dec;
  69.             } else {
  70.                 // copy pixels from encoded stream
  71.                 odd_pixel =  stream_byte & 1;
  72.                 rle_code = (stream_byte + 1) / 2;
  73.                 extra_byte = rle_code & 0x01;
  74.                 if (row_ptr + pixel_ptr + stream_byte > frame_size ||
  75.                     bytestream2_get_bytes_left(gb) < rle_code) {
  76.                     av_log(avctx, AV_LOG_ERROR,
  77.                            "MS RLE: frame/stream ptr just went out of bounds (copy)\n");
  78.                     return AVERROR_INVALIDDATA;
  79.                 }
  80.  
  81.                 for (i = 0; i < rle_code; i++) {
  82.                     if (pixel_ptr >= avctx->width)
  83.                         break;
  84.                     stream_byte = bytestream2_get_byteu(gb);
  85.                     pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
  86.                     pixel_ptr++;
  87.                     if (i + 1 == rle_code && odd_pixel)
  88.                         break;
  89.                     if (pixel_ptr >= avctx->width)
  90.                         break;
  91.                     pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
  92.                     pixel_ptr++;
  93.                 }
  94.  
  95.                 // if the RLE code is odd, skip a byte in the stream
  96.                 if (extra_byte)
  97.                     bytestream2_skip(gb, 1);
  98.             }
  99.         } else {
  100.             // decode a run of data
  101.             if (row_ptr + pixel_ptr + stream_byte > frame_size) {
  102.                 av_log(avctx, AV_LOG_ERROR,
  103.                        "MS RLE: frame ptr just went out of bounds (run)\n");
  104.                 return AVERROR_INVALIDDATA;
  105.             }
  106.             stream_byte = bytestream2_get_byte(gb);
  107.             for (i = 0; i < rle_code; i++) {
  108.                 if (pixel_ptr >= avctx->width)
  109.                     break;
  110.                 if ((i & 1) == 0)
  111.                     pic->data[0][row_ptr + pixel_ptr] = stream_byte >> 4;
  112.                 else
  113.                     pic->data[0][row_ptr + pixel_ptr] = stream_byte & 0x0F;
  114.                 pixel_ptr++;
  115.             }
  116.         }
  117.     }
  118.  
  119.     /* one last sanity check on the way out */
  120.     if (bytestream2_get_bytes_left(gb)) {
  121.         av_log(avctx, AV_LOG_ERROR,
  122.                "MS RLE: ended frame decode with %d bytes left over\n",
  123.                bytestream2_get_bytes_left(gb));
  124.         return AVERROR_INVALIDDATA;
  125.     }
  126.  
  127.     return 0;
  128. }
  129.  
  130.  
  131. static int msrle_decode_8_16_24_32(AVCodecContext *avctx, AVPicture *pic,
  132.                                    int depth, GetByteContext *gb)
  133. {
  134.     uint8_t *output, *output_end;
  135.     int p1, p2, line=avctx->height - 1, pos=0, i;
  136.     uint16_t pix16;
  137.     uint32_t pix32;
  138.     unsigned int width= FFABS(pic->linesize[0]) / (depth >> 3);
  139.  
  140.     output     = pic->data[0] + (avctx->height - 1) * pic->linesize[0];
  141.     output_end = output + FFABS(pic->linesize[0]);
  142.  
  143.     while (bytestream2_get_bytes_left(gb) > 0) {
  144.         p1 = bytestream2_get_byteu(gb);
  145.         if(p1 == 0) { //Escape code
  146.             p2 = bytestream2_get_byte(gb);
  147.             if(p2 == 0) { //End-of-line
  148.                 if (--line < 0) {
  149.                     if (bytestream2_get_be16(gb) == 1) { // end-of-picture
  150.                         return 0;
  151.                     } else {
  152.                         av_log(avctx, AV_LOG_ERROR,
  153.                                "Next line is beyond picture bounds (%d bytes left)\n",
  154.                                bytestream2_get_bytes_left(gb));
  155.                         return AVERROR_INVALIDDATA;
  156.                     }
  157.                 }
  158.                 output = pic->data[0] + line * pic->linesize[0];
  159.                 output_end = output + FFABS(pic->linesize[0]);
  160.                 pos = 0;
  161.                 continue;
  162.             } else if(p2 == 1) { //End-of-picture
  163.                 return 0;
  164.             } else if(p2 == 2) { //Skip
  165.                 p1 = bytestream2_get_byte(gb);
  166.                 p2 = bytestream2_get_byte(gb);
  167.                 line -= p2;
  168.                 pos += p1;
  169.                 if (line < 0 || pos >= width){
  170.                     av_log(avctx, AV_LOG_ERROR, "Skip beyond picture bounds\n");
  171.                     return -1;
  172.                 }
  173.                 output = pic->data[0] + line * pic->linesize[0] + pos * (depth >> 3);
  174.                 output_end = pic->data[0] + line * pic->linesize[0] + FFABS(pic->linesize[0]);
  175.                 continue;
  176.             }
  177.             // Copy data
  178.             if (output + p2 * (depth >> 3) > output_end) {
  179.                 bytestream2_skip(gb, 2 * (depth >> 3));
  180.                 continue;
  181.             } else if (bytestream2_get_bytes_left(gb) < p2 * (depth >> 3)) {
  182.                 av_log(avctx, AV_LOG_ERROR, "bytestream overrun\n");
  183.                 return AVERROR_INVALIDDATA;
  184.             }
  185.  
  186.             if ((depth == 8) || (depth == 24)) {
  187.                 bytestream2_get_bufferu(gb, output, p2 * (depth >> 3));
  188.                 output += p2 * (depth >> 3);
  189.  
  190.                 // RLE8 copy is actually padded - and runs are not!
  191.                 if(depth == 8 && (p2 & 1)) {
  192.                     bytestream2_skip(gb, 1);
  193.                 }
  194.             } else if (depth == 16) {
  195.                 for(i = 0; i < p2; i++) {
  196.                     *(uint16_t*)output = bytestream2_get_le16u(gb);
  197.                     output += 2;
  198.                 }
  199.             } else if (depth == 32) {
  200.                 for(i = 0; i < p2; i++) {
  201.                     *(uint32_t*)output = bytestream2_get_le32u(gb);
  202.                     output += 4;
  203.                 }
  204.             }
  205.             pos += p2;
  206.         } else { //run of pixels
  207.             uint8_t pix[3]; //original pixel
  208.             if (output + p1 * (depth >> 3) > output_end)
  209.                 continue;
  210.  
  211.             switch(depth){
  212.             case  8:
  213.                 pix[0] = bytestream2_get_byte(gb);
  214.                 memset(output, pix[0], p1);
  215.                 output += p1;
  216.                 break;
  217.             case 16:
  218.                 pix16  = bytestream2_get_le16(gb);
  219.                 for(i = 0; i < p1; i++) {
  220.                         *(uint16_t*)output = pix16;
  221.                         output += 2;
  222.                 }
  223.                 break;
  224.             case 24:
  225.                 pix[0] = bytestream2_get_byte(gb);
  226.                 pix[1] = bytestream2_get_byte(gb);
  227.                 pix[2] = bytestream2_get_byte(gb);
  228.                 for(i = 0; i < p1; i++) {
  229.                         *output++ = pix[0];
  230.                         *output++ = pix[1];
  231.                         *output++ = pix[2];
  232.                 }
  233.                 break;
  234.             case 32:
  235.                 pix32  = bytestream2_get_le32(gb);
  236.                 for(i = 0; i < p1; i++) {
  237.                         *(uint32_t*)output = pix32;
  238.                         output += 4;
  239.                 }
  240.                 break;
  241.             }
  242.             pos += p1;
  243.         }
  244.     }
  245.  
  246.     av_log(avctx, AV_LOG_WARNING, "MS RLE warning: no end-of-picture code\n");
  247.     return 0;
  248. }
  249.  
  250.  
  251. int ff_msrle_decode(AVCodecContext *avctx, AVPicture *pic,
  252.                     int depth, GetByteContext *gb)
  253. {
  254.     switch(depth){
  255.     case  4:
  256.         return msrle_decode_pal4(avctx, pic, gb);
  257.     case  8:
  258.     case 16:
  259.     case 24:
  260.     case 32:
  261.         return msrle_decode_8_16_24_32(avctx, pic, depth, gb);
  262.     default:
  263.         av_log(avctx, AV_LOG_ERROR, "Unknown depth %d\n", depth);
  264.         return -1;
  265.     }
  266. }
  267.