Mercurial > libavcodec.hg
comparison fraps.c @ 4140:a2247f4db5aa libavcodec
Fraps v2 and v4 support
author | kostya |
---|---|
date | Sun, 05 Nov 2006 04:57:14 +0000 |
parents | c8c591fe26f8 |
children | b03f19bc1698 |
comparison
equal
deleted
inserted
replaced
4139:8772709e26d0 | 4140:a2247f4db5aa |
---|---|
1 /* | 1 /* |
2 * Fraps FPS1 decoder | 2 * Fraps FPS1 decoder |
3 * Copyright (c) 2005 Roine Gustafsson | 3 * Copyright (c) 2005 Roine Gustafsson |
4 * Copyright (c) 2006 Konstantin Shishkov | |
4 * | 5 * |
5 * This file is part of FFmpeg. | 6 * This file is part of FFmpeg. |
6 * | 7 * |
7 * FFmpeg is free software; you can redistribute it and/or | 8 * FFmpeg is free software; you can redistribute it and/or |
8 * modify it under the terms of the GNU Lesser General Public | 9 * modify it under the terms of the GNU Lesser General Public |
22 | 23 |
23 /** | 24 /** |
24 * @file fraps.c | 25 * @file fraps.c |
25 * Lossless Fraps 'FPS1' decoder | 26 * Lossless Fraps 'FPS1' decoder |
26 * @author Roine Gustafsson <roine at users sf net> | 27 * @author Roine Gustafsson <roine at users sf net> |
28 * @author Konstantin Shishkov | |
27 * | 29 * |
28 * Only decodes version 0 and 1 files. | 30 * Only decodes version 0 and 1 files. |
29 * Codec algorithm for version 0 is taken from Transcode <www.transcoding.org> | 31 * Codec algorithm for version 0 is taken from Transcode <www.transcoding.org> |
30 * | 32 * |
31 * Version 2 files, which are the most commonly found Fraps files, cannot be | 33 * Version 2 files support by Konstantin Shishkov |
32 * decoded yet. | |
33 */ | 34 */ |
34 | 35 |
35 #include "avcodec.h" | 36 #include "avcodec.h" |
37 #include "bitstream.h" | |
38 #include "dsputil.h" | |
36 | 39 |
37 #define FPS_TAG MKTAG('F', 'P', 'S', 'x') | 40 #define FPS_TAG MKTAG('F', 'P', 'S', 'x') |
41 | |
42 /* symbol for Huffman tree node */ | |
43 #define HNODE -1 | |
44 | |
45 /** | |
46 * Huffman node | |
47 * FIXME one day this should belong to one general framework | |
48 */ | |
49 typedef struct Node{ | |
50 int16_t sym; | |
51 int16_t n0; | |
52 int count; | |
53 }Node; | |
38 | 54 |
39 /** | 55 /** |
40 * local variable storage | 56 * local variable storage |
41 */ | 57 */ |
42 typedef struct FrapsContext{ | 58 typedef struct FrapsContext{ |
43 AVCodecContext *avctx; | 59 AVCodecContext *avctx; |
44 AVFrame frame; | 60 AVFrame frame; |
61 Node nodes[512]; | |
62 uint8_t *tmpbuf; | |
63 DSPContext dsp; | |
45 } FrapsContext; | 64 } FrapsContext; |
46 | 65 |
47 | 66 |
48 /** | 67 /** |
49 * initializes decoder | 68 * initializes decoder |
58 avctx->has_b_frames = 0; | 77 avctx->has_b_frames = 0; |
59 avctx->pix_fmt= PIX_FMT_NONE; /* set in decode_frame */ | 78 avctx->pix_fmt= PIX_FMT_NONE; /* set in decode_frame */ |
60 | 79 |
61 s->avctx = avctx; | 80 s->avctx = avctx; |
62 s->frame.data[0] = NULL; | 81 s->frame.data[0] = NULL; |
82 s->tmpbuf = NULL; | |
83 | |
84 dsputil_init(&s->dsp, avctx); | |
63 | 85 |
64 return 0; | 86 return 0; |
65 } | 87 } |
66 | 88 |
89 /** | |
90 * Comparator - our nodes should ascend by count | |
91 * but with preserved symbol order | |
92 */ | |
93 static int huff_cmp(const Node *a, const Node *b){ | |
94 return (a->count - b->count)*256 + a->sym - b->sym; | |
95 } | |
96 | |
97 static void get_tree_codes(uint32_t *bits, int16_t *lens, Node *nodes, int node, uint32_t pfx, int pl) | |
98 { | |
99 int s; | |
100 | |
101 s = nodes[node].sym; | |
102 if(s != HNODE){ | |
103 bits[s] = pfx; | |
104 lens[s] = pl; | |
105 }else{ | |
106 pfx <<= 1; | |
107 pl++; | |
108 get_tree_codes(bits, lens, nodes, nodes[node].n0, pfx, pl); | |
109 pfx |= 1; | |
110 get_tree_codes(bits, lens, nodes, nodes[node].n0+1, pfx, pl); | |
111 } | |
112 } | |
113 | |
114 static int build_huff_tree(VLC *vlc, Node *nodes) | |
115 { | |
116 uint32_t bits[256]; | |
117 int16_t lens[256]; | |
118 | |
119 get_tree_codes(bits, lens, nodes, 510, 0, 0); | |
120 return init_vlc(vlc, 9, 256, lens, 2, 2, bits, 4, 4, 0); | |
121 } | |
122 | |
123 | |
124 /** | |
125 * decode Fraps v2 packed plane | |
126 */ | |
127 static int fraps2_decode_plane(FrapsContext *s, uint8_t *dst, int stride, int w, | |
128 int h, uint8_t *src, int size, int Uoff) | |
129 { | |
130 int i, j; | |
131 int cur_node; | |
132 GetBitContext gb; | |
133 VLC vlc; | |
134 int64_t sum = 0; | |
135 | |
136 for(i = 0; i < 256; i++){ | |
137 s->nodes[i].sym = i; | |
138 s->nodes[i].count = LE_32(src); | |
139 s->nodes[i].n0 = -2; | |
140 src += 4; | |
141 sum += s->nodes[i].count; | |
142 } | |
143 size -= 1024; | |
144 | |
145 if(sum >> 31) { | |
146 av_log(s->avctx, AV_LOG_ERROR, "Too high symbol frequencies. Tree construction is not possible\n"); | |
147 return -1; | |
148 } | |
149 qsort(s->nodes, 256, sizeof(Node), huff_cmp); | |
150 cur_node = 256; | |
151 // FIXME how it will handle nodes with zero count? | |
152 for(i = 0; i < 511; i += 2){ | |
153 s->nodes[cur_node].sym = HNODE; | |
154 s->nodes[cur_node].count = s->nodes[i].count + s->nodes[i+1].count; | |
155 s->nodes[cur_node].n0 = i; | |
156 for(j = cur_node; j > 0; j--){ | |
157 if(s->nodes[j].count >= s->nodes[j - 1].count) break; | |
158 FFSWAP(Node, s->nodes[j], s->nodes[j - 1]); | |
159 } | |
160 cur_node++; | |
161 } | |
162 if(build_huff_tree(&vlc, s->nodes) < 0){ | |
163 av_log(s->avctx, AV_LOG_ERROR, "Error building tree\n"); | |
164 return -1; | |
165 } | |
166 /* we have built Huffman table and are ready to decode plane */ | |
167 | |
168 /* convert bits so they may be used by standard bitreader */ | |
169 s->dsp.bswap_buf(s->tmpbuf, src, size >> 2); | |
170 | |
171 init_get_bits(&gb, s->tmpbuf, size * 8); | |
172 for(j = 0; j < h; j++){ | |
173 for(i = 0; i < w; i++){ | |
174 dst[i] = get_vlc2(&gb, vlc.table, 9, 3); | |
175 /* lines are stored as deltas between previous lines | |
176 * and we need to add 0x80 to the first lines of chroma planes | |
177 */ | |
178 if(j) dst[i] += dst[i - stride]; | |
179 else if(Uoff) dst[i] += 0x80; | |
180 } | |
181 dst += stride; | |
182 } | |
183 free_vlc(&vlc); | |
184 return 0; | |
185 } | |
67 | 186 |
68 /** | 187 /** |
69 * decode a frame | 188 * decode a frame |
70 * @param avctx codec context | 189 * @param avctx codec context |
71 * @param data output AVFrame | 190 * @param data output AVFrame |
84 uint32_t header; | 203 uint32_t header; |
85 unsigned int version,header_size; | 204 unsigned int version,header_size; |
86 unsigned int x, y; | 205 unsigned int x, y; |
87 uint32_t *buf32; | 206 uint32_t *buf32; |
88 uint32_t *luma1,*luma2,*cb,*cr; | 207 uint32_t *luma1,*luma2,*cb,*cr; |
208 uint32_t offs[4]; | |
209 int i, is_chroma, planes; | |
89 | 210 |
90 | 211 |
91 header = LE_32(buf); | 212 header = LE_32(buf); |
92 version = header & 0xff; | 213 version = header & 0xff; |
93 header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ | 214 header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ |
94 | 215 |
95 if (version > 1) { | 216 if (version > 2 && version != 4) { |
96 av_log(avctx, AV_LOG_ERROR, | 217 av_log(avctx, AV_LOG_ERROR, |
97 "This file is encoded with Fraps version %d. " \ | 218 "This file is encoded with Fraps version %d. " \ |
98 "This codec can only decode version 0 and 1.\n", version); | 219 "This codec can only decode version 0, 1, 2 and 4.\n", version); |
99 return -1; | 220 return -1; |
100 } | 221 } |
101 | 222 |
102 buf+=4; | 223 buf+=4; |
103 if (header_size == 8) | 224 if (header_size == 8) |
185 f->linesize[0]); | 306 f->linesize[0]); |
186 } | 307 } |
187 break; | 308 break; |
188 | 309 |
189 case 2: | 310 case 2: |
311 case 4: | |
190 /** | 312 /** |
191 * Fraps v2 sub-header description. All numbers are little-endian: | 313 * Fraps v2 is Huffman-coded YUV420 planes |
192 * (this is all guesswork) | 314 * Fraps v4 is the same except it works in grayscale |
193 * | |
194 * 0: DWORD 'FPSx' | |
195 * 4: DWORD 0x00000010 unknown, perhaps flags | |
196 * 8: DWORD off_2 offset to plane 2 | |
197 * 12: DWORD off_3 offset to plane 3 | |
198 * 16: 256xDWORD freqtbl_1 frequency table for plane 1 | |
199 * 1040: plane_1 | |
200 * ... | |
201 * off_2: 256xDWORD freqtbl_2 frequency table for plane 2 | |
202 * plane_2 | |
203 * ... | |
204 * off_3: 256xDWORD freqtbl_3 frequency table for plane 3 | |
205 * plane_3 | |
206 */ | 315 */ |
207 if ((BE_32(buf) != FPS_TAG)||(buf_size < (3*1024 + 8))) { | 316 avctx->pix_fmt = (version == 2) ? PIX_FMT_YUV420P : PIX_FMT_GRAY8; |
317 planes = (version == 2) ? 3 : 1; | |
318 f->reference = 1; | |
319 f->buffer_hints = FF_BUFFER_HINTS_VALID | | |
320 FF_BUFFER_HINTS_PRESERVE | | |
321 FF_BUFFER_HINTS_REUSABLE; | |
322 if (avctx->reget_buffer(avctx, f)) { | |
323 av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); | |
324 return -1; | |
325 } | |
326 /* skip frame */ | |
327 if(buf_size == 8) { | |
328 f->pict_type = FF_P_TYPE; | |
329 f->key_frame = 0; | |
330 break; | |
331 } | |
332 f->pict_type = FF_I_TYPE; | |
333 f->key_frame = 1; | |
334 if ((LE_32(buf) != FPS_TAG)||(buf_size < (planes*1024 + 24))) { | |
208 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); | 335 av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); |
209 return -1; | 336 return -1; |
210 } | 337 } |
211 | 338 for(i = 0; i < planes; i++) { |
212 /* NOT FINISHED */ | 339 offs[i] = LE_32(buf + 4 + i * 4); |
213 | 340 if(offs[i] >= buf_size || (i && offs[i] <= offs[i - 1] + 1024)) { |
341 av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); | |
342 return -1; | |
343 } | |
344 } | |
345 offs[planes] = buf_size; | |
346 for(i = 0; i < planes; i++){ | |
347 is_chroma = !!i; | |
348 s->tmpbuf = av_realloc(s->tmpbuf, offs[i + 1] - offs[i] - 1024); | |
349 if(fraps2_decode_plane(s, f->data[i], f->linesize[i], avctx->width >> is_chroma, | |
350 avctx->height >> is_chroma, buf + offs[i], offs[i + 1] - offs[i], is_chroma) < 0) { | |
351 av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); | |
352 return -1; | |
353 } | |
354 } | |
214 break; | 355 break; |
215 } | 356 } |
216 | 357 |
217 *frame = *f; | 358 *frame = *f; |
218 *data_size = sizeof(AVFrame); | 359 *data_size = sizeof(AVFrame); |
231 FrapsContext *s = (FrapsContext*)avctx->priv_data; | 372 FrapsContext *s = (FrapsContext*)avctx->priv_data; |
232 | 373 |
233 if (s->frame.data[0]) | 374 if (s->frame.data[0]) |
234 avctx->release_buffer(avctx, &s->frame); | 375 avctx->release_buffer(avctx, &s->frame); |
235 | 376 |
377 av_freep(&s->tmpbuf); | |
236 return 0; | 378 return 0; |
237 } | 379 } |
238 | 380 |
239 | 381 |
240 AVCodec fraps_decoder = { | 382 AVCodec fraps_decoder = { |