fraps.c 12 KB
Newer Older
1 2 3
/*
 * Fraps FPS1 decoder
 * Copyright (c) 2005 Roine Gustafsson
4
 * Copyright (c) 2006 Konstantin Shishkov
5
 *
6 7 8
 * This file is part of FFmpeg.
 *
 * FFmpeg is free software; you can redistribute it and/or
9 10
 * modify it under the terms of the GNU Lesser General Public
 * 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 15 16 17 18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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 26
 * Lossless Fraps 'FPS1' decoder
 * @author Roine Gustafsson <roine at users sf net>
27
 * @author Konstantin Shishkov
28
 *
29 30
 * Codec algorithm for version 0 is taken from Transcode <www.transcoding.org>
 *
31
 * Version 2 files support by Konstantin Shishkov
32
 */
33

34
#include "avcodec.h"
35
#include "get_bits.h"
36 37
#include "huffman.h"
#include "bytestream.h"
38
#include "dsputil.h"
39

Mike Melanson's avatar
Mike Melanson committed
40
#define FPS_TAG MKTAG('F', 'P', 'S', 'x')
41 42 43 44 45 46 47

/**
 * local variable storage
 */
typedef struct FrapsContext{
    AVCodecContext *avctx;
    AVFrame frame;
48 49
    uint8_t *tmpbuf;
    DSPContext dsp;
50 51 52 53 54 55 56 57
} FrapsContext;


/**
 * initializes decoder
 * @param avctx codec context
 * @return 0 on success or negative if fails
 */
58
static av_cold int decode_init(AVCodecContext *avctx)
59 60 61 62 63 64 65
{
    FrapsContext * const s = avctx->priv_data;

    avctx->coded_frame = (AVFrame*)&s->frame;
    avctx->pix_fmt= PIX_FMT_NONE; /* set in decode_frame */

    s->avctx = avctx;
66 67 68
    s->tmpbuf = NULL;

    dsputil_init(&s->dsp, avctx);
69 70 71 72

    return 0;
}

73 74 75 76
/**
 * Comparator - our nodes should ascend by count
 * but with preserved symbol order
 */
77 78
static int huff_cmp(const void *va, const void *vb){
    const Node *a = va, *b = vb;
79 80 81 82 83 84 85
    return (a->count - b->count)*256 + a->sym - b->sym;
}

/**
 * decode Fraps v2 packed plane
 */
static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w,
86 87
                               int h, const uint8_t *src, int size, int Uoff,
                               const int step)
88 89 90 91
{
    int i, j;
    GetBitContext gb;
    VLC vlc;
92
    Node nodes[512];
93

94 95 96
    for(i = 0; i < 256; i++)
        nodes[i].count = bytestream_get_le32(&src);
    size -= 1024;
97 98
    if (ff_huff_build_tree(s->avctx, &vlc, 256, nodes, huff_cmp,
                           FF_HUFFMAN_FLAG_ZERO_COUNT) < 0)
99 100 101 102
        return -1;
    /* we have built Huffman table and are ready to decode plane */

    /* 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 106

    init_get_bits(&gb, s->tmpbuf, size * 8);
    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 110 111 112 113 114 115 116 117 118 119
            /* lines are stored as deltas between previous lines
             * and we need to add 0x80 to the first lines of chroma planes
             */
            if(j) dst[i] += dst[i - stride];
            else if(Uoff) dst[i] += 0x80;
        }
        dst += stride;
    }
    free_vlc(&vlc);
    return 0;
}
120 121 122 123 124 125 126 127 128 129

/**
 * decode a frame
 * @param avctx codec context
 * @param data output AVFrame
 * @param data_size size of output data or 0 if no picture is returned
 * @param buf input data frame
 * @param buf_size size of input data frame
 * @return number of consumed bytes on success or negative if decode fails
 */
130
static int decode_frame(AVCodecContext *avctx,
131
                        void *data, int *data_size,
132
                        AVPacket *avpkt)
133
{
134 135
    const uint8_t *buf = avpkt->data;
    int buf_size = avpkt->size;
136 137 138 139 140 141
    FrapsContext * const s = avctx->priv_data;
    AVFrame *frame = data;
    AVFrame * const f = (AVFrame*)&s->frame;
    uint32_t header;
    unsigned int version,header_size;
    unsigned int x, y;
Michael Niedermayer's avatar
Michael Niedermayer committed
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 150 151
    version = header & 0xff;
    header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */

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 157 158 159 160 161
        return -1;
    }

    buf+=4;
    if (header_size == 8)
        buf+=4;
162

163 164 165 166 167 168
    switch(version) {
    case 0:
    default:
        /* Fraps v0 is a reordered YUV420 */
        avctx->pix_fmt = PIX_FMT_YUV420P;

169
        if ( (buf_size != avctx->width*avctx->height*3/2+header_size) &&
170 171
             (buf_size != header_size) ) {
            av_log(avctx, AV_LOG_ERROR,
172
                   "Invalid frame length %d (should be %d)\n",
173 174 175
                   buf_size, avctx->width*avctx->height*3/2+header_size);
            return -1;
        }
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 180 181 182
                   avctx->width, avctx->height);
            return -1;
        }

183 184 185
        f->reference = 1;
        f->buffer_hints = FF_BUFFER_HINTS_VALID |
                          FF_BUFFER_HINTS_PRESERVE |
186 187 188 189
                          FF_BUFFER_HINTS_REUSABLE;
        if (avctx->reget_buffer(avctx, f)) {
            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
            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 194
        f->key_frame = f->pict_type == FF_I_TYPE;

195
        if (f->pict_type == FF_I_TYPE) {
Michael Niedermayer's avatar
Michael Niedermayer committed
196
            buf32=(const uint32_t*)buf;
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217
            for(y=0; y<avctx->height/2; y++){
                luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ];
                luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ];
                cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ];
                cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ];
                for(x=0; x<avctx->width; x+=8){
                    *(luma1++) = *(buf32++);
                    *(luma1++) = *(buf32++);
                    *(luma2++) = *(buf32++);
                    *(luma2++) = *(buf32++);
                    *(cr++) = *(buf32++);
                    *(cb++) = *(buf32++);
                }
            }
        }
        break;

    case 1:
        /* Fraps v1 is an upside-down BGR24 */
        avctx->pix_fmt = PIX_FMT_BGR24;

218
        if ( (buf_size != avctx->width*avctx->height*3+header_size) &&
219
             (buf_size != header_size) ) {
220
            av_log(avctx, AV_LOG_ERROR,
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
                   "Invalid frame length %d (should be %d)\n",
                   buf_size, avctx->width*avctx->height*3+header_size);
            return -1;
        }

        f->reference = 1;
        f->buffer_hints = FF_BUFFER_HINTS_VALID |
                          FF_BUFFER_HINTS_PRESERVE |
                          FF_BUFFER_HINTS_REUSABLE;
        if (avctx->reget_buffer(avctx, f)) {
            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
            return -1;
        }
        /* bit 31 means same as previous pic */
        f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE;
        f->key_frame = f->pict_type == FF_I_TYPE;

        if (f->pict_type == FF_I_TYPE) {
            for(y=0; y<avctx->height; y++)
                memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ],
                       &buf[y*avctx->width*3],
242
                       3*avctx->width);
243 244 245 246
        }
        break;

    case 2:
247
    case 4:
248
        /**
249
         * Fraps v2 is Huffman-coded YUV420 planes
250
         * Fraps v4 is virtually the same
251
         */
252 253
        avctx->pix_fmt = PIX_FMT_YUV420P;
        planes = 3;
254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
        f->reference = 1;
        f->buffer_hints = FF_BUFFER_HINTS_VALID |
                          FF_BUFFER_HINTS_PRESERVE |
                          FF_BUFFER_HINTS_REUSABLE;
        if (avctx->reget_buffer(avctx, f)) {
            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
            return -1;
        }
        /* skip frame */
        if(buf_size == 8) {
            f->pict_type = FF_P_TYPE;
            f->key_frame = 0;
            break;
        }
        f->pict_type = FF_I_TYPE;
        f->key_frame = 1;
270
        if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) {
271 272 273
            av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
            return -1;
        }
274
        for(i = 0; i < planes; i++) {
275
            offs[i] = AV_RL32(buf + 4 + i * 4);
276 277 278 279 280 281 282 283
            if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) {
                av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i);
                return -1;
            }
        }
        offs[planes] = buf_size;
        for(i = 0; i < planes; i++){
            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 288 289 290
                av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i);
                return -1;
            }
        }
291
        break;
292
    case 3:
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327
    case 5:
        /* Virtually the same as version 4, but is for RGB24 */
        avctx->pix_fmt = PIX_FMT_BGR24;
        planes = 3;
        f->reference = 1;
        f->buffer_hints = FF_BUFFER_HINTS_VALID |
                          FF_BUFFER_HINTS_PRESERVE |
                          FF_BUFFER_HINTS_REUSABLE;
        if (avctx->reget_buffer(avctx, f)) {
            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
            return -1;
        }
        /* skip frame */
        if(buf_size == 8) {
            f->pict_type = FF_P_TYPE;
            f->key_frame = 0;
            break;
        }
        f->pict_type = FF_I_TYPE;
        f->key_frame = 1;
        if ((AV_RL32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) {
            av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
            return -1;
        }
        for(i = 0; i < planes; i++) {
            offs[i] = AV_RL32(buf + 4 + i * 4);
            if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) {
                av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i);
                return -1;
            }
        }
        offs[planes] = buf_size;
        for(i = 0; i < planes; i++){
            s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024 + FF_INPUT_BUFFER_PADDING_SIZE);
            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 330 331 332
                av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i);
                return -1;
            }
        }
333 334 335
        // convert pseudo-YUV into real RGB
        for(j = 0; j < avctx->height; j++){
            for(i = 0; i < avctx->width; i++){
336 337
                f->data[0][0 + i*3 + j*f->linesize[0]] += f->data[0][1 + i*3 + j*f->linesize[0]];
                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 344 345 346 347 348 349 350 351 352 353 354
    }

    *frame = *f;
    *data_size = sizeof(AVFrame);

    return buf_size;
}


/**
 * closes decoder
 * @param avctx codec context
 * @return 0 on success or negative if fails
 */
355
static av_cold int decode_end(AVCodecContext *avctx)
356 357 358 359 360 361
{
    FrapsContext *s = (FrapsContext*)avctx->priv_data;

    if (s->frame.data[0])
        avctx->release_buffer(avctx, &s->frame);

362
    av_freep(&s->tmpbuf);
363 364 365 366 367 368 369 370 371 372 373 374 375 376
    return 0;
}


AVCodec fraps_decoder = {
    "fraps",
    CODEC_TYPE_VIDEO,
    CODEC_ID_FRAPS,
    sizeof(FrapsContext),
    decode_init,
    NULL,
    decode_end,
    decode_frame,
    CODEC_CAP_DR1,
377
    .long_name = NULL_IF_CONFIG_SMALL("Fraps"),
378
};