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