1/* 2 * Fraps FPS1 decoder 3 * Copyright (c) 2005 Roine Gustafsson 4 * Copyright (c) 2006 Konstantin Shishkov 5 * 6 * This file is part of FFmpeg. 7 * 8 * FFmpeg is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * FFmpeg is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with FFmpeg; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 */ 22 23/** 24 * @file libavcodec/fraps.c 25 * Lossless Fraps 'FPS1' decoder 26 * @author Roine Gustafsson <roine at users sf net> 27 * @author Konstantin Shishkov 28 * 29 * Codec algorithm for version 0 is taken from Transcode <www.transcoding.org> 30 * 31 * Version 2 files support by Konstantin Shishkov 32 */ 33 34#include "avcodec.h" 35#include "bitstream.h" 36#include "huffman.h" 37#include "bytestream.h" 38#include "dsputil.h" 39 40#define FPS_TAG MKTAG('F', 'P', 'S', 'x') 41 42/** 43 * local variable storage 44 */ 45typedef struct FrapsContext{ 46 AVCodecContext *avctx; 47 AVFrame frame; 48 uint8_t *tmpbuf; 49 DSPContext dsp; 50} FrapsContext; 51 52 53/** 54 * initializes decoder 55 * @param avctx codec context 56 * @return 0 on success or negative if fails 57 */ 58static av_cold int decode_init(AVCodecContext *avctx) 59{ 60 FrapsContext * const s = avctx->priv_data; 61 62 avctx->coded_frame = (AVFrame*)&s->frame; 63 avctx->pix_fmt= PIX_FMT_NONE; /* set in decode_frame */ 64 65 s->avctx = avctx; 66 s->frame.data[0] = NULL; 67 s->tmpbuf = NULL; 68 69 dsputil_init(&s->dsp, avctx); 70 71 return 0; 72} 73 74/** 75 * Comparator - our nodes should ascend by count 76 * but with preserved symbol order 77 */ 78static int huff_cmp(const void *va, const void *vb){ 79 const Node *a = va, *b = vb; 80 return (a->count - b->count)*256 + a->sym - b->sym; 81} 82 83/** 84 * decode Fraps v2 packed plane 85 */ 86static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w, 87 int h, const uint8_t *src, int size, int Uoff, 88 const int step) 89{ 90 int i, j; 91 GetBitContext gb; 92 VLC vlc; 93 Node nodes[512]; 94 95 for(i = 0; i < 256; i++) 96 nodes[i].count = bytestream_get_le32(&src); 97 size -= 1024; 98 if (ff_huff_build_tree(s->avctx, &vlc, 256, nodes, huff_cmp, 99 FF_HUFFMAN_FLAG_ZERO_COUNT) < 0) 100 return -1; 101 /* we have built Huffman table and are ready to decode plane */ 102 103 /* convert bits so they may be used by standard bitreader */ 104 s->dsp.bswap_buf((uint32_t *)s->tmpbuf, (const uint32_t *)src, size >> 2); 105 106 init_get_bits(&gb, s->tmpbuf, size * 8); 107 for(j = 0; j < h; j++){ 108 for(i = 0; i < w*step; i += step){ 109 dst[i] = get_vlc2(&gb, vlc.table, 9, 3); 110 /* lines are stored as deltas between previous lines 111 * and we need to add 0x80 to the first lines of chroma planes 112 */ 113 if(j) dst[i] += dst[i - stride]; 114 else if(Uoff) dst[i] += 0x80; 115 } 116 dst += stride; 117 } 118 free_vlc(&vlc); 119 return 0; 120} 121 122/** 123 * decode a frame 124 * @param avctx codec context 125 * @param data output AVFrame 126 * @param data_size size of output data or 0 if no picture is returned 127 * @param buf input data frame 128 * @param buf_size size of input data frame 129 * @return number of consumed bytes on success or negative if decode fails 130 */ 131static int decode_frame(AVCodecContext *avctx, 132 void *data, int *data_size, 133 const uint8_t *buf, int buf_size) 134{ 135 FrapsContext * const s = avctx->priv_data; 136 AVFrame *frame = data; 137 AVFrame * const f = (AVFrame*)&s->frame; 138 uint32_t header; 139 unsigned int version,header_size; 140 unsigned int x, y; 141 const uint32_t *buf32; 142 uint32_t *luma1,*luma2,*cb,*cr; 143 uint32_t offs[4]; 144 int i, j, is_chroma, planes; 145 146 147 header = AV_RL32(buf); 148 version = header & 0xff; 149 header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ 150 151 if (version > 5) { 152 av_log(avctx, AV_LOG_ERROR, 153 "This file is encoded with Fraps version %d. " \ 154 "This codec can only decode versions <= 5.\n", version); 155 return -1; 156 } 157 158 buf+=4; 159 if (header_size == 8) 160 buf+=4; 161 162 switch(version) { 163 case 0: 164 default: 165 /* Fraps v0 is a reordered YUV420 */ 166 avctx->pix_fmt = PIX_FMT_YUV420P; 167 168 if ( (buf_size != avctx->width*avctx->height*3/2+header_size) && 169 (buf_size != header_size) ) { 170 av_log(avctx, AV_LOG_ERROR, 171 "Invalid frame length %d (should be %d)\n", 172 buf_size, avctx->width*avctx->height*3/2+header_size); 173 return -1; 174 } 175 176 if (( (avctx->width % 8) != 0) || ( (avctx->height % 2) != 0 )) { 177 av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", 178 avctx->width, avctx->height); 179 return -1; 180 } 181 182 f->reference = 1; 183 f->buffer_hints = FF_BUFFER_HINTS_VALID | 184 FF_BUFFER_HINTS_PRESERVE | 185 FF_BUFFER_HINTS_REUSABLE; 186 if (avctx->reget_buffer(avctx, f)) { 187 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 188 return -1; 189 } 190 /* bit 31 means same as previous pic */ 191 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; 192 f->key_frame = f->pict_type == FF_I_TYPE; 193 194 if (f->pict_type == FF_I_TYPE) { 195 buf32=(const uint32_t*)buf; 196 for(y=0; y<avctx->height/2; y++){ 197 luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ]; 198 luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ]; 199 cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ]; 200 cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ]; 201 for(x=0; x<avctx->width; x+=8){ 202 *(luma1++) = *(buf32++); 203 *(luma1++) = *(buf32++); 204 *(luma2++) = *(buf32++); 205 *(luma2++) = *(buf32++); 206 *(cr++) = *(buf32++); 207 *(cb++) = *(buf32++); 208 } 209 } 210 } 211 break; 212 213 case 1: 214 /* Fraps v1 is an upside-down BGR24 */ 215 avctx->pix_fmt = PIX_FMT_BGR24; 216 217 if ( (buf_size != avctx->width*avctx->height*3+header_size) && 218 (buf_size != header_size) ) { 219 av_log(avctx, AV_LOG_ERROR, 220 "Invalid frame length %d (should be %d)\n", 221 buf_size, avctx->width*avctx->height*3+header_size); 222 return -1; 223 } 224 225 f->reference = 1; 226 f->buffer_hints = FF_BUFFER_HINTS_VALID | 227 FF_BUFFER_HINTS_PRESERVE | 228 FF_BUFFER_HINTS_REUSABLE; 229 if (avctx->reget_buffer(avctx, f)) { 230 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 231 return -1; 232 } 233 /* bit 31 means same as previous pic */ 234 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; 235 f->key_frame = f->pict_type == FF_I_TYPE; 236 237 if (f->pict_type == FF_I_TYPE) { 238 for(y=0; y<avctx->height; y++) 239 memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ], 240 &buf[y*avctx->width*3], 241 f->linesize[0]); 242 } 243 break; 244 245 case 2: 246 case 4: 247 /** 248 * Fraps v2 is Huffman-coded YUV420 planes 249 * Fraps v4 is virtually the same 250 */ 251 avctx->pix_fmt = PIX_FMT_YUV420P; 252 planes = 3; 253 f->reference = 1; 254 f->buffer_hints = FF_BUFFER_HINTS_VALID | 255 FF_BUFFER_HINTS_PRESERVE | 256 FF_BUFFER_HINTS_REUSABLE; 257 if (avctx->reget_buffer(avctx, f)) { 258 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 259 return -1; 260 } 261 /* skip frame */ 262 if(buf_size == 8) { 263 f->pict_type = FF_P_TYPE; 264 f->key_frame = 0; 265 break; 266 } 267 f->pict_type = FF_I_TYPE; 268 f->key_frame = 1; 269 if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) { 270 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); 271 return -1; 272 } 273 for(i = 0; i < planes; i++) { 274 offs[i] = AV_RL32(buf + 4 + i * 4); 275 if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) { 276 av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); 277 return -1; 278 } 279 } 280 offs[planes] = buf_size; 281 for(i = 0; i < planes; i++){ 282 is_chroma = !!i; 283 s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024 + FF_INPUT_BUFFER_PADDING_SIZE); 284 if(fraps2_decode_plane(s, f->data[i], f->linesize[i], avctx->width >> is_chroma, 285 avctx->height >> is_chroma, buf + offs[i], offs[i + 1] - offs[i], is_chroma, 1) < 0) { 286 av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); 287 return -1; 288 } 289 } 290 break; 291 case 3: 292 case 5: 293 /* Virtually the same as version 4, but is for RGB24 */ 294 avctx->pix_fmt = PIX_FMT_BGR24; 295 planes = 3; 296 f->reference = 1; 297 f->buffer_hints = FF_BUFFER_HINTS_VALID | 298 FF_BUFFER_HINTS_PRESERVE | 299 FF_BUFFER_HINTS_REUSABLE; 300 if (avctx->reget_buffer(avctx, f)) { 301 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 302 return -1; 303 } 304 /* skip frame */ 305 if(buf_size == 8) { 306 f->pict_type = FF_P_TYPE; 307 f->key_frame = 0; 308 break; 309 } 310 f->pict_type = FF_I_TYPE; 311 f->key_frame = 1; 312 if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) { 313 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); 314 return -1; 315 } 316 for(i = 0; i < planes; i++) { 317 offs[i] = AV_RL32(buf + 4 + i * 4); 318 if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) { 319 av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); 320 return -1; 321 } 322 } 323 offs[planes] = buf_size; 324 for(i = 0; i < planes; i++){ 325 s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024 + FF_INPUT_BUFFER_PADDING_SIZE); 326 if(fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)), -f->linesize[0], 327 avctx->width, avctx->height, buf + offs[i], offs[i + 1] - offs[i], 0, 3) < 0) { 328 av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); 329 return -1; 330 } 331 } 332 // convert pseudo-YUV into real RGB 333 for(j = 0; j < avctx->height; j++){ 334 for(i = 0; i < avctx->width; i++){ 335 f->data[0][0 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]]; 336 f->data[0][2 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]]; 337 } 338 } 339 break; 340 } 341 342 *frame = *f; 343 *data_size = sizeof(AVFrame); 344 345 return buf_size; 346} 347 348 349/** 350 * closes decoder 351 * @param avctx codec context 352 * @return 0 on success or negative if fails 353 */ 354static av_cold int decode_end(AVCodecContext *avctx) 355{ 356 FrapsContext *s = (FrapsContext*)avctx->priv_data; 357 358 if (s->frame.data[0]) 359 avctx->release_buffer(avctx, &s->frame); 360 361 av_freep(&s->tmpbuf); 362 return 0; 363} 364 365 366AVCodec fraps_decoder = { 367 "fraps", 368 CODEC_TYPE_VIDEO, 369 CODEC_ID_FRAPS, 370 sizeof(FrapsContext), 371 decode_init, 372 NULL, 373 decode_end, 374 decode_frame, 375 CODEC_CAP_DR1, 376 .long_name = NULL_IF_CONFIG_SMALL("Fraps"), 377}; 378