blob: 7a7673f73fe6d7fb4142724af6cc21530fddbd01
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 "bswapdsp.h" |
39 | #include "internal.h" |
40 | #include "thread.h" |
41 | |
42 | #define FPS_TAG MKTAG('F', 'P', 'S', 'x') |
43 | #define VLC_BITS 11 |
44 | |
45 | /** |
46 | * local variable storage |
47 | */ |
48 | typedef struct FrapsContext { |
49 | AVCodecContext *avctx; |
50 | BswapDSPContext bdsp; |
51 | uint8_t *tmpbuf; |
52 | int tmpbuf_size; |
53 | } FrapsContext; |
54 | |
55 | |
56 | /** |
57 | * initializes decoder |
58 | * @param avctx codec context |
59 | * @return 0 on success or negative if fails |
60 | */ |
61 | static av_cold int decode_init(AVCodecContext *avctx) |
62 | { |
63 | FrapsContext * const s = avctx->priv_data; |
64 | |
65 | s->avctx = avctx; |
66 | s->tmpbuf = NULL; |
67 | |
68 | ff_bswapdsp_init(&s->bdsp); |
69 | |
70 | return 0; |
71 | } |
72 | |
73 | /** |
74 | * Comparator - our nodes should ascend by count |
75 | * but with preserved symbol order |
76 | */ |
77 | static int huff_cmp(const void *va, const void *vb) |
78 | { |
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 | */ |
86 | static 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, ret; |
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 ((ret = ff_huff_build_tree(s->avctx, &vlc, 256, VLC_BITS, |
99 | nodes, huff_cmp, |
100 | FF_HUFFMAN_FLAG_ZERO_COUNT)) < 0) |
101 | return ret; |
102 | /* we have built Huffman table and are ready to decode plane */ |
103 | |
104 | /* convert bits so they may be used by standard bitreader */ |
105 | s->bdsp.bswap_buf((uint32_t *) s->tmpbuf, |
106 | (const uint32_t *) src, size >> 2); |
107 | |
108 | if ((ret = init_get_bits8(&gb, s->tmpbuf, size)) < 0) |
109 | return ret; |
110 | |
111 | for (j = 0; j < h; j++) { |
112 | for (i = 0; i < w*step; i += step) { |
113 | dst[i] = get_vlc2(&gb, vlc.table, VLC_BITS, 3); |
114 | /* lines are stored as deltas between previous lines |
115 | * and we need to add 0x80 to the first lines of chroma planes |
116 | */ |
117 | if (j) |
118 | dst[i] += dst[i - stride]; |
119 | else if (Uoff) |
120 | dst[i] += 0x80; |
121 | if (get_bits_left(&gb) < 0) { |
122 | ff_free_vlc(&vlc); |
123 | return AVERROR_INVALIDDATA; |
124 | } |
125 | } |
126 | dst += stride; |
127 | } |
128 | ff_free_vlc(&vlc); |
129 | return 0; |
130 | } |
131 | |
132 | static int decode_frame(AVCodecContext *avctx, |
133 | void *data, int *got_frame, |
134 | AVPacket *avpkt) |
135 | { |
136 | FrapsContext * const s = avctx->priv_data; |
137 | const uint8_t *buf = avpkt->data; |
138 | int buf_size = avpkt->size; |
139 | ThreadFrame frame = { .f = data }; |
140 | AVFrame * const f = data; |
141 | uint32_t header; |
142 | unsigned int version,header_size; |
143 | unsigned int x, y; |
144 | const uint32_t *buf32; |
145 | uint32_t *luma1,*luma2,*cb,*cr; |
146 | uint32_t offs[4]; |
147 | int i, j, ret, is_chroma; |
148 | const int planes = 3; |
149 | int is_pal; |
150 | uint8_t *out; |
151 | |
152 | if (buf_size < 4) { |
153 | av_log(avctx, AV_LOG_ERROR, "Packet is too short\n"); |
154 | return AVERROR_INVALIDDATA; |
155 | } |
156 | |
157 | header = AV_RL32(buf); |
158 | version = header & 0xff; |
159 | is_pal = buf[1] == 2 && version == 1; |
160 | header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ |
161 | |
162 | if (version > 5) { |
163 | avpriv_report_missing_feature(avctx, "Fraps version %u", version); |
164 | return AVERROR_PATCHWELCOME; |
165 | } |
166 | |
167 | buf += header_size; |
168 | |
169 | if (is_pal) { |
170 | unsigned needed_size = avctx->width * avctx->height + 1024; |
171 | needed_size += header_size; |
172 | if (buf_size != needed_size) { |
173 | av_log(avctx, AV_LOG_ERROR, |
174 | "Invalid frame length %d (should be %d)\n", |
175 | buf_size, needed_size); |
176 | return AVERROR_INVALIDDATA; |
177 | } |
178 | } else if (version < 2) { |
179 | unsigned needed_size = avctx->width * avctx->height * 3; |
180 | if (version == 0) needed_size /= 2; |
181 | needed_size += header_size; |
182 | /* bit 31 means same as previous pic */ |
183 | if (header & (1U<<31)) { |
184 | *got_frame = 0; |
185 | return buf_size; |
186 | } |
187 | if (buf_size != needed_size) { |
188 | av_log(avctx, AV_LOG_ERROR, |
189 | "Invalid frame length %d (should be %d)\n", |
190 | buf_size, needed_size); |
191 | return AVERROR_INVALIDDATA; |
192 | } |
193 | } else { |
194 | /* skip frame */ |
195 | if (buf_size == 8) { |
196 | *got_frame = 0; |
197 | return buf_size; |
198 | } |
199 | if (AV_RL32(buf) != FPS_TAG || buf_size < planes*1024 + 24) { |
200 | av_log(avctx, AV_LOG_ERROR, "error in data stream\n"); |
201 | return AVERROR_INVALIDDATA; |
202 | } |
203 | for (i = 0; i < planes; i++) { |
204 | offs[i] = AV_RL32(buf + 4 + i * 4); |
205 | if (offs[i] >= buf_size - header_size || (i && offs[i] <= offs[i - 1] + 1024)) { |
206 | av_log(avctx, AV_LOG_ERROR, "plane %i offset is out of bounds\n", i); |
207 | return AVERROR_INVALIDDATA; |
208 | } |
209 | } |
210 | offs[planes] = buf_size - header_size; |
211 | for (i = 0; i < planes; i++) { |
212 | av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size, offs[i + 1] - offs[i] - 1024); |
213 | if (!s->tmpbuf) |
214 | return AVERROR(ENOMEM); |
215 | } |
216 | } |
217 | |
218 | f->pict_type = AV_PICTURE_TYPE_I; |
219 | f->key_frame = 1; |
220 | |
221 | avctx->pix_fmt = version & 1 ? is_pal ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P; |
222 | avctx->color_range = version & 1 ? AVCOL_RANGE_UNSPECIFIED |
223 | : AVCOL_RANGE_JPEG; |
224 | avctx->colorspace = version & 1 ? AVCOL_SPC_UNSPECIFIED : AVCOL_SPC_BT709; |
225 | |
226 | if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) |
227 | return ret; |
228 | |
229 | switch (version) { |
230 | case 0: |
231 | default: |
232 | /* Fraps v0 is a reordered YUV420 */ |
233 | if (((avctx->width % 8) != 0) || ((avctx->height % 2) != 0)) { |
234 | av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", |
235 | avctx->width, avctx->height); |
236 | return AVERROR_INVALIDDATA; |
237 | } |
238 | |
239 | buf32 = (const uint32_t*)buf; |
240 | for (y = 0; y < avctx->height / 2; y++) { |
241 | luma1 = (uint32_t*)&f->data[0][ y * 2 * f->linesize[0] ]; |
242 | luma2 = (uint32_t*)&f->data[0][ (y * 2 + 1) * f->linesize[0] ]; |
243 | cr = (uint32_t*)&f->data[1][ y * f->linesize[1] ]; |
244 | cb = (uint32_t*)&f->data[2][ y * f->linesize[2] ]; |
245 | for (x = 0; x < avctx->width; x += 8) { |
246 | *luma1++ = *buf32++; |
247 | *luma1++ = *buf32++; |
248 | *luma2++ = *buf32++; |
249 | *luma2++ = *buf32++; |
250 | *cr++ = *buf32++; |
251 | *cb++ = *buf32++; |
252 | } |
253 | } |
254 | break; |
255 | |
256 | case 1: |
257 | if (is_pal) { |
258 | uint32_t *pal = (uint32_t *)f->data[1]; |
259 | |
260 | for (y = 0; y < 256; y++) { |
261 | pal[y] = AV_RL32(buf) | 0xFF000000; |
262 | buf += 4; |
263 | } |
264 | |
265 | for (y = 0; y <avctx->height; y++) |
266 | memcpy(&f->data[0][y * f->linesize[0]], |
267 | &buf[y * avctx->width], |
268 | avctx->width); |
269 | } else { |
270 | /* Fraps v1 is an upside-down BGR24 */ |
271 | for (y = 0; y<avctx->height; y++) |
272 | memcpy(&f->data[0][(avctx->height - y - 1) * f->linesize[0]], |
273 | &buf[y * avctx->width * 3], |
274 | 3 * avctx->width); |
275 | } |
276 | break; |
277 | |
278 | case 2: |
279 | case 4: |
280 | /** |
281 | * Fraps v2 is Huffman-coded YUV420 planes |
282 | * Fraps v4 is virtually the same |
283 | */ |
284 | for (i = 0; i < planes; i++) { |
285 | is_chroma = !!i; |
286 | if ((ret = fraps2_decode_plane(s, f->data[i], f->linesize[i], |
287 | avctx->width >> is_chroma, |
288 | avctx->height >> is_chroma, |
289 | buf + offs[i], offs[i + 1] - offs[i], |
290 | is_chroma, 1)) < 0) { |
291 | av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); |
292 | return ret; |
293 | } |
294 | } |
295 | break; |
296 | case 3: |
297 | case 5: |
298 | /* Virtually the same as version 4, but is for RGB24 */ |
299 | for (i = 0; i < planes; i++) { |
300 | if ((ret = fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)), |
301 | -f->linesize[0], avctx->width, avctx->height, |
302 | buf + offs[i], offs[i + 1] - offs[i], 0, 3)) < 0) { |
303 | av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); |
304 | return ret; |
305 | } |
306 | } |
307 | out = f->data[0]; |
308 | // convert pseudo-YUV into real RGB |
309 | for (j = 0; j < avctx->height; j++) { |
310 | uint8_t *line_end = out + 3*avctx->width; |
311 | while (out < line_end) { |
312 | out[0] += out[1]; |
313 | out[2] += out[1]; |
314 | out += 3; |
315 | } |
316 | out += f->linesize[0] - 3*avctx->width; |
317 | } |
318 | break; |
319 | } |
320 | |
321 | *got_frame = 1; |
322 | |
323 | return buf_size; |
324 | } |
325 | |
326 | |
327 | /** |
328 | * closes decoder |
329 | * @param avctx codec context |
330 | * @return 0 on success or negative if fails |
331 | */ |
332 | static av_cold int decode_end(AVCodecContext *avctx) |
333 | { |
334 | FrapsContext *s = (FrapsContext*)avctx->priv_data; |
335 | |
336 | av_freep(&s->tmpbuf); |
337 | return 0; |
338 | } |
339 | |
340 | |
341 | AVCodec ff_fraps_decoder = { |
342 | .name = "fraps", |
343 | .long_name = NULL_IF_CONFIG_SMALL("Fraps"), |
344 | .type = AVMEDIA_TYPE_VIDEO, |
345 | .id = AV_CODEC_ID_FRAPS, |
346 | .priv_data_size = sizeof(FrapsContext), |
347 | .init = decode_init, |
348 | .close = decode_end, |
349 | .decode = decode_frame, |
350 | .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, |
351 | .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, |
352 | }; |
353 |