Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * RL2 Video Decoder
  3.  * Copyright (C) 2008 Sascha Sommer (saschasommer@freenet.de)
  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.  * RL2 Video Decoder
  25.  * @author Sascha Sommer (saschasommer@freenet.de)
  26.  * @see http://wiki.multimedia.cx/index.php?title=RL2
  27.  */
  28.  
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32.  
  33. #include "libavutil/internal.h"
  34. #include "libavutil/intreadwrite.h"
  35. #include "libavutil/mem.h"
  36. #include "avcodec.h"
  37. #include "internal.h"
  38.  
  39.  
  40. #define EXTRADATA1_SIZE (6 + 256 * 3) ///< video base, clr count, palette
  41.  
  42. typedef struct Rl2Context {
  43.     AVCodecContext *avctx;
  44.  
  45.     uint16_t video_base;  ///< initial drawing offset
  46.     uint32_t clr_count;   ///< number of used colors (currently unused)
  47.     uint8_t *back_frame;  ///< background frame
  48.     uint32_t palette[AVPALETTE_COUNT];
  49. } Rl2Context;
  50.  
  51. /**
  52.  * Run Length Decode a single 320x200 frame
  53.  * @param s rl2 context
  54.  * @param in input buffer
  55.  * @param size input buffer size
  56.  * @param out output buffer
  57.  * @param stride stride of the output buffer
  58.  * @param video_base offset of the rle data inside the frame
  59.  */
  60. static void rl2_rle_decode(Rl2Context *s, const uint8_t *in, int size,
  61.                                uint8_t *out, int stride, int video_base)
  62. {
  63.     int base_x = video_base % s->avctx->width;
  64.     int base_y = video_base / s->avctx->width;
  65.     int stride_adj = stride - s->avctx->width;
  66.     int i;
  67.     const uint8_t *back_frame = s->back_frame;
  68.     const uint8_t *in_end     = in + size;
  69.     const uint8_t *out_end    = out + stride * s->avctx->height;
  70.     uint8_t *line_end;
  71.  
  72.     /** copy start of the background frame */
  73.     for (i = 0; i <= base_y; i++) {
  74.         if (s->back_frame)
  75.             memcpy(out, back_frame, s->avctx->width);
  76.         out        += stride;
  77.         back_frame += s->avctx->width;
  78.     }
  79.     back_frame += base_x - s->avctx->width;
  80.     line_end    = out - stride_adj;
  81.     out        += base_x - stride;
  82.  
  83.     /** decode the variable part of the frame */
  84.     while (in < in_end) {
  85.         uint8_t val = *in++;
  86.         int len     = 1;
  87.         if (val >= 0x80) {
  88.             if (in >= in_end)
  89.                 break;
  90.             len = *in++;
  91.             if (!len)
  92.                 break;
  93.         }
  94.  
  95.         if (len >= out_end - out)
  96.             break;
  97.  
  98.         if (s->back_frame)
  99.             val |= 0x80;
  100.         else
  101.             val &= ~0x80;
  102.  
  103.         while (len--) {
  104.             *out++ = (val == 0x80) ? *back_frame : val;
  105.             back_frame++;
  106.             if (out == line_end) {
  107.                  out      += stride_adj;
  108.                  line_end += stride;
  109.                  if (len >= out_end - out)
  110.                      break;
  111.             }
  112.         }
  113.     }
  114.  
  115.     /** copy the rest from the background frame */
  116.     if (s->back_frame) {
  117.         while (out < out_end) {
  118.             memcpy(out, back_frame, line_end - out);
  119.             back_frame += line_end - out;
  120.             out         = line_end + stride_adj;
  121.             line_end   += stride;
  122.         }
  123.     }
  124. }
  125.  
  126.  
  127. /**
  128.  * Initialize the decoder
  129.  * @param avctx decoder context
  130.  * @return 0 success, -1 on error
  131.  */
  132. static av_cold int rl2_decode_init(AVCodecContext *avctx)
  133. {
  134.     Rl2Context *s = avctx->priv_data;
  135.     int back_size;
  136.     int i;
  137.  
  138.     s->avctx       = avctx;
  139.     avctx->pix_fmt = AV_PIX_FMT_PAL8;
  140.  
  141.     /** parse extra data */
  142.     if (!avctx->extradata || avctx->extradata_size < EXTRADATA1_SIZE) {
  143.         av_log(avctx, AV_LOG_ERROR, "invalid extradata size\n");
  144.         return AVERROR(EINVAL);
  145.     }
  146.  
  147.     /** get frame_offset */
  148.     s->video_base = AV_RL16(&avctx->extradata[0]);
  149.     s->clr_count  = AV_RL32(&avctx->extradata[2]);
  150.  
  151.     if (s->video_base >= avctx->width * avctx->height) {
  152.         av_log(avctx, AV_LOG_ERROR, "invalid video_base\n");
  153.         return AVERROR_INVALIDDATA;
  154.     }
  155.  
  156.     /** initialize palette */
  157.     for (i = 0; i < AVPALETTE_COUNT; i++)
  158.         s->palette[i] = 0xFFU << 24 | AV_RB24(&avctx->extradata[6 + i * 3]);
  159.  
  160.     /** decode background frame if present */
  161.     back_size = avctx->extradata_size - EXTRADATA1_SIZE;
  162.  
  163.     if (back_size > 0) {
  164.         uint8_t *back_frame = av_mallocz(avctx->width*avctx->height);
  165.         if (!back_frame)
  166.             return AVERROR(ENOMEM);
  167.         rl2_rle_decode(s, avctx->extradata + EXTRADATA1_SIZE, back_size,
  168.                        back_frame, avctx->width, 0);
  169.         s->back_frame = back_frame;
  170.     }
  171.     return 0;
  172. }
  173.  
  174.  
  175. static int rl2_decode_frame(AVCodecContext *avctx,
  176.                             void *data, int *got_frame,
  177.                             AVPacket *avpkt)
  178. {
  179.     AVFrame *frame     = data;
  180.     const uint8_t *buf = avpkt->data;
  181.     int ret, buf_size  = avpkt->size;
  182.     Rl2Context *s = avctx->priv_data;
  183.  
  184.     if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
  185.         return ret;
  186.  
  187.     /** run length decode */
  188.     rl2_rle_decode(s, buf, buf_size, frame->data[0], frame->linesize[0],
  189.                    s->video_base);
  190.  
  191.     /** make the palette available on the way out */
  192.     memcpy(frame->data[1], s->palette, AVPALETTE_SIZE);
  193.  
  194.     *got_frame = 1;
  195.  
  196.     /** report that the buffer was completely consumed */
  197.     return buf_size;
  198. }
  199.  
  200.  
  201. /**
  202.  * Uninit decoder
  203.  * @param avctx decoder context
  204.  * @return 0 success, -1 on error
  205.  */
  206. static av_cold int rl2_decode_end(AVCodecContext *avctx)
  207. {
  208.     Rl2Context *s = avctx->priv_data;
  209.  
  210.     av_free(s->back_frame);
  211.  
  212.     return 0;
  213. }
  214.  
  215.  
  216. AVCodec ff_rl2_decoder = {
  217.     .name           = "rl2",
  218.     .long_name      = NULL_IF_CONFIG_SMALL("RL2 video"),
  219.     .type           = AVMEDIA_TYPE_VIDEO,
  220.     .id             = AV_CODEC_ID_RL2,
  221.     .priv_data_size = sizeof(Rl2Context),
  222.     .init           = rl2_decode_init,
  223.     .close          = rl2_decode_end,
  224.     .decode         = rl2_decode_frame,
  225.     .capabilities   = CODEC_CAP_DR1,
  226. };
  227.