Browse code

Fraps FPS1 video decoder (v1 & v2), courtesy of Roine Gustafsson <roine at users sf net>

Originally committed as revision 4264 to svn://svn.ffmpeg.org/ffmpeg/trunk

Mike Melanson authored on 2005/05/18 07:47:34
Showing 8 changed files
... ...
@@ -14,6 +14,7 @@ Brian Foley
14 14
 Arpad Gereoffy
15 15
 Philip Gladstone
16 16
 Vladimir Gneushev
17
+Roine Gustafsson
17 18
 David Hammerton
18 19
 Wolfgang Hesseler
19 20
 Falk Hueffner
... ...
@@ -15,6 +15,7 @@ version <next>
15 15
 - Winnov WNV1 video decoder
16 16
 - Autodesk Animator Studio Codec (AASC) decoder
17 17
 - Indeo 2 video decoder
18
+- Fraps FPS1 video decoder
18 19
 
19 20
 version 0.4.9-pre1:
20 21
 
... ...
@@ -775,6 +775,7 @@ following image formats are supported:
775 775
 @item LOCO                   @tab     @tab  X @tab 
776 776
 @item Winnov WNV1            @tab     @tab  X @tab 
777 777
 @item Autodesk Animator Studio Codec  @tab     @tab  X @tab fourcc: AASC
778
+@item Fraps FPS1             @tab     @tab  X @tab 
778 779
 @end multitable
779 780
 
780 781
 @code{X} means that the encoding (resp. decoding) is supported.
... ...
@@ -55,6 +55,9 @@ endif
55 55
 ifeq ($(CONFIG_FOURXM_DECODER),yes)
56 56
     OBJS+= 4xm.o
57 57
 endif
58
+ifeq ($(CONFIG_FRAPS_DECODER),yes)
59
+    OBJS+= fraps.o
60
+endif
58 61
 ifneq ($(CONFIG_H261_DECODER)$(CONFIG_H261_ENCODER),)
59 62
     OBJS+= h261.o
60 63
 endif
... ...
@@ -280,6 +280,9 @@ void avcodec_register_all(void)
280 280
 #ifdef CONFIG_AASC_DECODER
281 281
     register_avcodec(&aasc_decoder);
282 282
 #endif //CONFIG_AASC_DECODER
283
+#ifdef CONFIG_FRAPS_DECODER
284
+    register_avcodec(&fraps_decoder);
285
+#endif //CONFIG_FRAPS_DECODER
283 286
 #ifdef CONFIG_FAAD
284 287
 #ifdef CONFIG_AAC_DECODER
285 288
     register_avcodec(&aac_decoder);
... ...
@@ -17,7 +17,7 @@ extern "C" {
17 17
 
18 18
 #define FFMPEG_VERSION_INT     0x000409
19 19
 #define FFMPEG_VERSION         "0.4.9-pre1"
20
-#define LIBAVCODEC_BUILD       4754
20
+#define LIBAVCODEC_BUILD       4755
21 21
 
22 22
 #define LIBAVCODEC_VERSION_INT FFMPEG_VERSION_INT
23 23
 #define LIBAVCODEC_VERSION     FFMPEG_VERSION
... ...
@@ -109,6 +109,7 @@ enum CodecID {
109 109
     CODEC_ID_WNV1,
110 110
     CODEC_ID_AASC,
111 111
     CODEC_ID_INDEO2,
112
+    CODEC_ID_FRAPS,
112 113
 
113 114
     /* various pcm "codecs" */
114 115
     CODEC_ID_PCM_S16LE= 0x10000,
... ...
@@ -2019,6 +2020,7 @@ extern AVCodec alac_decoder;
2019 2019
 extern AVCodec ws_snd1_decoder;
2020 2020
 extern AVCodec indeo2_decoder;
2021 2021
 extern AVCodec vorbis_decoder;
2022
+extern AVCodec fraps_decoder;
2022 2023
 
2023 2024
 /* pcm codecs */
2024 2025
 #define PCM_CODEC(id, name) \
2025 2026
new file mode 100644
... ...
@@ -0,0 +1,248 @@
0
+/*
1
+ * Fraps FPS1 decoder
2
+ * Copyright (c) 2005 Roine Gustafsson
3
+ *
4
+ * This library is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License as published by the Free Software Foundation; either
7
+ * version 2 of the License, or (at your option) any later version.
8
+ *
9
+ * This library is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * Lesser General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Lesser General Public
15
+ * License along with this library; if not, write to the Free Software
16
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
+ *
18
+ */
19
+ 
20
+/**
21
+ * @file fraps.c
22
+ * Lossless Fraps 'FPS1' decoder
23
+ * @author Roine Gustafsson <roine at users sf net>
24
+ * 
25
+ * Only decodes version 0 and 1 files.
26
+ * Codec algorithm for version 0 is taken from Transcode <www.transcoding.org>
27
+ *
28
+ * Version 2 files, which are the most commonly found Fraps files, cannot be
29
+ * decoded yet.
30
+ */
31
+ 
32
+#include "avcodec.h"
33
+
34
+#define FPS_TAG MKTAG('F', 'P', 'S', '1')
35
+
36
+/**
37
+ * local variable storage
38
+ */
39
+typedef struct FrapsContext{
40
+    AVCodecContext *avctx;
41
+    AVFrame frame;
42
+} FrapsContext;
43
+
44
+
45
+/**
46
+ * initializes decoder
47
+ * @param avctx codec context
48
+ * @return 0 on success or negative if fails
49
+ */
50
+static int decode_init(AVCodecContext *avctx)
51
+{
52
+    FrapsContext * const s = avctx->priv_data;
53
+
54
+    avctx->coded_frame = (AVFrame*)&s->frame;
55
+    avctx->has_b_frames = 0;
56
+    avctx->pix_fmt= PIX_FMT_NONE; /* set in decode_frame */
57
+
58
+    s->avctx = avctx;
59
+    s->frame.data[0] = NULL;    
60
+
61
+    return 0;
62
+}
63
+
64
+
65
+/**
66
+ * decode a frame
67
+ * @param avctx codec context
68
+ * @param data output AVFrame
69
+ * @param data_size size of output data or 0 if no picture is returned
70
+ * @param buf input data frame
71
+ * @param buf_size size of input data frame
72
+ * @return number of consumed bytes on success or negative if decode fails
73
+ */
74
+static int decode_frame(AVCodecContext *avctx, 
75
+                        void *data, int *data_size,
76
+                        uint8_t *buf, int buf_size)
77
+{
78
+    FrapsContext * const s = avctx->priv_data;
79
+    AVFrame *frame = data;
80
+    AVFrame * const f = (AVFrame*)&s->frame;
81
+    uint32_t header;
82
+    unsigned int version,header_size;
83
+    unsigned int x, y;
84
+    uint32_t *buf32;
85
+    uint32_t *luma1,*luma2,*cb,*cr;
86
+
87
+
88
+    header = LE_32(buf);
89
+    version = header & 0xff;
90
+    header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */
91
+
92
+    if (version > 1) {
93
+        av_log(avctx, AV_LOG_ERROR, 
94
+               "This file is encoded with Fraps version %d. " \
95
+               "This codec can only decode version 0 and 1.\n", version);
96
+        return -1;
97
+    }
98
+
99
+    buf+=4;
100
+    if (header_size == 8)
101
+        buf+=4;
102
+        
103
+    switch(version) {
104
+    case 0:
105
+    default:
106
+        /* Fraps v0 is a reordered YUV420 */
107
+        avctx->pix_fmt = PIX_FMT_YUV420P;
108
+
109
+        if ( (buf_size != avctx->width*avctx->height*3/2+header_size) && 
110
+             (buf_size != header_size) ) {
111
+            av_log(avctx, AV_LOG_ERROR,
112
+                   "Invalid frame length %d (should be %d)\n", 
113
+                   buf_size, avctx->width*avctx->height*3/2+header_size);
114
+            return -1;
115
+        }
116
+        
117
+        if (( (avctx->width % 8) != 0) || ( (avctx->height % 2) != 0 )) {
118
+            av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", 
119
+                   avctx->width, avctx->height);
120
+            return -1;
121
+        }
122
+
123
+        f->reference = 1; 
124
+        f->buffer_hints = FF_BUFFER_HINTS_VALID | 
125
+                          FF_BUFFER_HINTS_PRESERVE | 
126
+                          FF_BUFFER_HINTS_REUSABLE;
127
+        if (avctx->reget_buffer(avctx, f)) {
128
+            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
129
+            return -1;
130
+        }        
131
+        /* bit 31 means same as previous pic */
132
+        f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE; 
133
+        f->key_frame = f->pict_type == FF_I_TYPE;
134
+
135
+        if (f->pict_type == FF_I_TYPE) { 
136
+            buf32=(uint32_t*)buf;
137
+            for(y=0; y<avctx->height/2; y++){
138
+                luma1=(uint32_t*)&f->data[0][ y*2*f->linesize[0] ];
139
+                luma2=(uint32_t*)&f->data[0][ (y*2+1)*f->linesize[0] ];
140
+                cr=(uint32_t*)&f->data[1][ y*f->linesize[1] ];
141
+                cb=(uint32_t*)&f->data[2][ y*f->linesize[2] ];
142
+                for(x=0; x<avctx->width; x+=8){
143
+                    *(luma1++) = *(buf32++);
144
+                    *(luma1++) = *(buf32++);
145
+                    *(luma2++) = *(buf32++);
146
+                    *(luma2++) = *(buf32++);
147
+                    *(cr++) = *(buf32++);
148
+                    *(cb++) = *(buf32++);
149
+                }
150
+            }
151
+        }
152
+        break;
153
+
154
+    case 1:
155
+        /* Fraps v1 is an upside-down BGR24 */
156
+        avctx->pix_fmt = PIX_FMT_BGR24;
157
+
158
+        if ( (buf_size != avctx->width*avctx->height*3+header_size) && 
159
+             (buf_size != header_size) ) {
160
+            av_log(avctx, AV_LOG_ERROR, 
161
+                   "Invalid frame length %d (should be %d)\n",
162
+                   buf_size, avctx->width*avctx->height*3+header_size);
163
+            return -1;
164
+        }
165
+
166
+        f->reference = 1;
167
+        f->buffer_hints = FF_BUFFER_HINTS_VALID |
168
+                          FF_BUFFER_HINTS_PRESERVE |
169
+                          FF_BUFFER_HINTS_REUSABLE;
170
+        if (avctx->reget_buffer(avctx, f)) {
171
+            av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
172
+            return -1;
173
+        }
174
+        /* bit 31 means same as previous pic */
175
+        f->pict_type = (header & (1<<31))? FF_P_TYPE : FF_I_TYPE;
176
+        f->key_frame = f->pict_type == FF_I_TYPE;
177
+
178
+        if (f->pict_type == FF_I_TYPE) {
179
+            for(y=0; y<avctx->height; y++)
180
+                memcpy(&f->data[0][ (avctx->height-y)*f->linesize[0] ],
181
+                       &buf[y*avctx->width*3],
182
+                       f->linesize[0]);
183
+        }
184
+        break;
185
+
186
+    case 2:
187
+        /**
188
+         * Fraps v2 sub-header description. All numbers are little-endian:
189
+         * (this is all guesswork)
190
+         *
191
+         *       0:     DWORD 'FPSx'
192
+         *       4:     DWORD 0x00000010   unknown, perhaps flags
193
+         *       8:     DWORD off_2        offset to plane 2
194
+         *      12:     DWORD off_3        offset to plane 3
195
+         *      16: 256xDWORD freqtbl_1    frequency table for plane 1
196
+         *    1040:           plane_1
197
+         *     ...
198
+         *   off_2: 256xDWORD freqtbl_2    frequency table for plane 2
199
+         *                    plane_2
200
+         *    ...
201
+         *   off_3: 256xDWORD freqtbl_3    frequency table for plane 3
202
+         *                    plane_3
203
+         */
204
+        if ((BE_32(buf) != FPS_TAG)||(buf_size < (3*1024 + 8))) {
205
+            av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n");
206
+            return -1;
207
+        }
208
+
209
+        /* NOT FINISHED */
210
+
211
+        break;
212
+    }
213
+
214
+    *frame = *f;
215
+    *data_size = sizeof(AVFrame);
216
+
217
+    return buf_size;
218
+}
219
+
220
+
221
+/**
222
+ * closes decoder
223
+ * @param avctx codec context
224
+ * @return 0 on success or negative if fails
225
+ */
226
+static int decode_end(AVCodecContext *avctx)
227
+{
228
+    FrapsContext *s = (FrapsContext*)avctx->priv_data;
229
+
230
+    if (s->frame.data[0])
231
+        avctx->release_buffer(avctx, &s->frame);
232
+
233
+    return 0;
234
+}
235
+
236
+
237
+AVCodec fraps_decoder = {
238
+    "fraps",
239
+    CODEC_TYPE_VIDEO,
240
+    CODEC_ID_FRAPS,
241
+    sizeof(FrapsContext),
242
+    decode_init,
243
+    NULL,
244
+    decode_end,
245
+    decode_frame,
246
+    CODEC_CAP_DR1,
247
+};
... ...
@@ -182,6 +182,7 @@ const CodecTag codec_bmp_tags[] = {
182 182
     { CODEC_ID_WNV1, MKTAG('W', 'N', 'V', '1') },
183 183
     { CODEC_ID_AASC, MKTAG('A', 'A', 'S', 'C') },
184 184
     { CODEC_ID_INDEO2, MKTAG('R', 'T', '2', '1') },
185
+    { CODEC_ID_FRAPS, MKTAG('F', 'P', 'S', '1') },
185 186
     { CODEC_ID_RAWVIDEO, 0 },
186 187
     { 0, 0 },
187 188
 };