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 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 "get_bits.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->tmpbuf = NULL; 67 68 dsputil_init(&s->dsp, avctx); 69 70 return 0; 71} 72 73/** 74 * Comparator - our nodes should ascend by count 75 * but with preserved symbol order 76 */ 77static int huff_cmp(const void *va, const void *vb){ 78 const Node *a = va, *b = vb; 79 return (a->count - b->count)*256 + a->sym - b->sym; 80} 81 82/** 83 * decode Fraps v2 packed plane 84 */ 85static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w, 86 int h, const uint8_t *src, int size, int Uoff, 87 const int step) 88{ 89 int i, j; 90 GetBitContext gb; 91 VLC vlc; 92 Node nodes[512]; 93 94 for(i = 0; i < 256; i++) 95 nodes[i].count = bytestream_get_le32(&src); 96 size -= 1024; 97 if (ff_huff_build_tree(s->avctx, &vlc, 256, nodes, huff_cmp, 98 FF_HUFFMAN_FLAG_ZERO_COUNT) < 0) 99 return -1; 100 /* we have built Huffman table and are ready to decode plane */ 101 102 /* convert bits so they may be used by standard bitreader */ 103 s->dsp.bswap_buf((uint32_t *)s->tmpbuf, (const uint32_t *)src, size >> 2); 104 105 init_get_bits(&gb, s->tmpbuf, size * 8); 106 for(j = 0; j < h; j++){ 107 for(i = 0; i < w*step; i += step){ 108 dst[i] = get_vlc2(&gb, vlc.table, 9, 3); 109 /* lines are stored as deltas between previous lines 110 * and we need to add 0x80 to the first lines of chroma planes 111 */ 112 if(j) dst[i] += dst[i - stride]; 113 else if(Uoff) dst[i] += 0x80; 114 } 115 dst += stride; 116 } 117 free_vlc(&vlc); 118 return 0; 119} 120 121/** 122 * decode a frame 123 * @param avctx codec context 124 * @param data output AVFrame 125 * @param data_size size of output data or 0 if no picture is returned 126 * @param buf input data frame 127 * @param buf_size size of input data frame 128 * @return number of consumed bytes on success or negative if decode fails 129 */ 130static int decode_frame(AVCodecContext *avctx, 131 void *data, int *data_size, 132 AVPacket *avpkt) 133{ 134 const uint8_t *buf = avpkt->data; 135 int buf_size = avpkt->size; 136 FrapsContext * const s = avctx->priv_data; 137 AVFrame *frame = data; 138 AVFrame * const f = (AVFrame*)&s->frame; 139 uint32_t header; 140 unsigned int version,header_size; 141 unsigned int x, y; 142 const uint32_t *buf32; 143 uint32_t *luma1,*luma2,*cb,*cr; 144 uint32_t offs[4]; 145 int i, j, is_chroma, planes; 146 147 148 header = AV_RL32(buf); 149 version = header & 0xff; 150 header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ 151 152 if (version > 5) { 153 av_log(avctx, AV_LOG_ERROR, 154 "This file is encoded with Fraps version %d. " \ 155 "This codec can only decode versions <= 5.\n", version); 156 return -1; 157 } 158 159 buf+=4; 160 if (header_size == 8) 161 buf+=4; 162 163 switch(version) { 164 case 0: 165 default: 166 /* Fraps v0 is a reordered YUV420 */ 167 avctx->pix_fmt = PIX_FMT_YUV420P; 168 169 if ( (buf_size != avctx->width*avctx->height*3/2+header_size) && 170 (buf_size != header_size) ) { 171 av_log(avctx, AV_LOG_ERROR, 172 "Invalid frame length %d (should be %d)\n", 173 buf_size, avctx->width*avctx->height*3/2+header_size); 174 return -1; 175 } 176 177 if (( (avctx->width % 8) != 0) || ( (avctx->height % 2) != 0 )) { 178 av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", 179 avctx->width, avctx->height); 180 return -1; 181 } 182 183 f->reference = 1; 184 f->buffer_hints = FF_BUFFER_HINTS_VALID | 185 FF_BUFFER_HINTS_PRESERVE | 186 FF_BUFFER_HINTS_REUSABLE; 187 if (avctx->reget_buffer(avctx, f)) { 188 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 189 return -1; 190 } 191 /* bit 31 means same as previous pic */ 192 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; 193 f->key_frame = f->pict_type == FF_I_TYPE; 194 195 if (f->pict_type == FF_I_TYPE) { 196 buf32=(const uint32_t*)buf; 197 for(y=0; y<avctx->height/2; y++){ 198 luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ]; 199 luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ]; 200 cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ]; 201 cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ]; 202 for(x=0; x<avctx->width; x+=8){ 203 *(luma1++) = *(buf32++); 204 *(luma1++) = *(buf32++); 205 *(luma2++) = *(buf32++); 206 *(luma2++) = *(buf32++); 207 *(cr++) = *(buf32++); 208 *(cb++) = *(buf32++); 209 } 210 } 211 } 212 break; 213 214 case 1: 215 /* Fraps v1 is an upside-down BGR24 */ 216 avctx->pix_fmt = PIX_FMT_BGR24; 217 218 if ( (buf_size != avctx->width*avctx->height*3+header_size) && 219 (buf_size != header_size) ) { 220 av_log(avctx, AV_LOG_ERROR, 221 "Invalid frame length %d (should be %d)\n", 222 buf_size, avctx->width*avctx->height*3+header_size); 223 return -1; 224 } 225 226 f->reference = 1; 227 f->buffer_hints = FF_BUFFER_HINTS_VALID | 228 FF_BUFFER_HINTS_PRESERVE | 229 FF_BUFFER_HINTS_REUSABLE; 230 if (avctx->reget_buffer(avctx, f)) { 231 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 232 return -1; 233 } 234 /* bit 31 means same as previous pic */ 235 f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; 236 f->key_frame = f->pict_type == FF_I_TYPE; 237 238 if (f->pict_type == FF_I_TYPE) { 239 for(y=0; y<avctx->height; y++) 240 memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ], 241 &buf[y*avctx->width*3], 242 3*avctx->width); 243 } 244 break; 245 246 case 2: 247 case 4: 248 /** 249 * Fraps v2 is Huffman-coded YUV420 planes 250 * Fraps v4 is virtually the same 251 */ 252 avctx->pix_fmt = PIX_FMT_YUV420P; 253 planes = 3; 254 f->reference = 1; 255 f->buffer_hints = FF_BUFFER_HINTS_VALID | 256 FF_BUFFER_HINTS_PRESERVE | 257 FF_BUFFER_HINTS_REUSABLE; 258 if (avctx->reget_buffer(avctx, f)) { 259 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 260 return -1; 261 } 262 /* skip frame */ 263 if(buf_size == 8) { 264 f->pict_type = FF_P_TYPE; 265 f->key_frame = 0; 266 break; 267 } 268 f->pict_type = FF_I_TYPE; 269 f->key_frame = 1; 270 if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) { 271 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); 272 return -1; 273 } 274 for(i = 0; i < planes; i++) { 275 offs[i] = AV_RL32(buf + 4 + i * 4); 276 if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) { 277 av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); 278 return -1; 279 } 280 } 281 offs[planes] = buf_size; 282 for(i = 0; i < planes; i++){ 283 is_chroma = !!i; 284 s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024 + FF_INPUT_BUFFER_PADDING_SIZE); 285 if(fraps2_decode_plane(s, f->data[i], f->linesize[i], avctx->width >> is_chroma, 286 avctx->height >> is_chroma, buf + offs[i], offs[i + 1] - offs[i], is_chroma, 1) < 0) { 287 av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); 288 return -1; 289 } 290 } 291 break; 292 case 3: 293 case 5: 294 /* Virtually the same as version 4, but is for RGB24 */ 295 avctx->pix_fmt = PIX_FMT_BGR24; 296 planes = 3; 297 f->reference = 1; 298 f->buffer_hints = FF_BUFFER_HINTS_VALID | 299 FF_BUFFER_HINTS_PRESERVE | 300 FF_BUFFER_HINTS_REUSABLE; 301 if (avctx->reget_buffer(avctx, f)) { 302 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); 303 return -1; 304 } 305 /* skip frame */ 306 if(buf_size == 8) { 307 f->pict_type = FF_P_TYPE; 308 f->key_frame = 0; 309 break; 310 } 311 f->pict_type = FF_I_TYPE; 312 f->key_frame = 1; 313 if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) { 314 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); 315 return -1; 316 } 317 for(i = 0; i < planes; i++) { 318 offs[i] = AV_RL32(buf + 4 + i * 4); 319 if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) { 320 av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); 321 return -1; 322 } 323 } 324 offs[planes] = buf_size; 325 for(i = 0; i < planes; i++){ 326 s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024 + FF_INPUT_BUFFER_PADDING_SIZE); 327 if(fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)), -f->linesize[0], 328 avctx->width, avctx->height, buf + offs[i], offs[i + 1] - offs[i], 0, 3) < 0) { 329 av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); 330 return -1; 331 } 332 } 333 // convert pseudo-YUV into real RGB 334 for(j = 0; j < avctx->height; j++){ 335 for(i = 0; i < avctx->width; i++){ 336 f->data[0][0 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]]; 337 f->data[0][2 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]]; 338 } 339 } 340 break; 341 } 342 343 *frame = *f; 344 *data_size = sizeof(AVFrame); 345 346 return buf_size; 347} 348 349 350/** 351 * closes decoder 352 * @param avctx codec context 353 * @return 0 on success or negative if fails 354 */ 355static av_cold int decode_end(AVCodecContext *avctx) 356{ 357 FrapsContext *s = (FrapsContext*)avctx->priv_data; 358 359 if (s->frame.data[0]) 360 avctx->release_buffer(avctx, &s->frame); 361 362 av_freep(&s->tmpbuf); 363 return 0; 364} 365 366 367AVCodec fraps_decoder = { 368 "fraps", 369 AVMEDIA_TYPE_VIDEO, 370 CODEC_ID_FRAPS, 371 sizeof(FrapsContext), 372 decode_init, 373 NULL, 374 decode_end, 375 decode_frame, 376 CODEC_CAP_DR1, 377 .long_name = NULL_IF_CONFIG_SMALL("Fraps"), 378}; 379