Commit | Line | Data |
---|---|---|
2ba45a60 DM |
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 | init_get_bits(&gb, s->tmpbuf, size * 8); | |
109 | for (j = 0; j < h; j++) { | |
110 | for (i = 0; i < w*step; i += step) { | |
111 | dst[i] = get_vlc2(&gb, vlc.table, VLC_BITS, 3); | |
112 | /* lines are stored as deltas between previous lines | |
113 | * and we need to add 0x80 to the first lines of chroma planes | |
114 | */ | |
115 | if (j) | |
116 | dst[i] += dst[i - stride]; | |
117 | else if (Uoff) | |
118 | dst[i] += 0x80; | |
119 | if (get_bits_left(&gb) < 0) { | |
120 | ff_free_vlc(&vlc); | |
121 | return AVERROR_INVALIDDATA; | |
122 | } | |
123 | } | |
124 | dst += stride; | |
125 | } | |
126 | ff_free_vlc(&vlc); | |
127 | return 0; | |
128 | } | |
129 | ||
130 | static int decode_frame(AVCodecContext *avctx, | |
131 | void *data, int *got_frame, | |
132 | AVPacket *avpkt) | |
133 | { | |
134 | FrapsContext * const s = avctx->priv_data; | |
135 | const uint8_t *buf = avpkt->data; | |
136 | int buf_size = avpkt->size; | |
137 | ThreadFrame frame = { .f = data }; | |
138 | AVFrame * const f = data; | |
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, ret, is_chroma; | |
146 | const int planes = 3; | |
147 | uint8_t *out; | |
148 | ||
149 | if (buf_size < 4) { | |
150 | av_log(avctx, AV_LOG_ERROR, "Packet is too short\n"); | |
151 | return AVERROR_INVALIDDATA; | |
152 | } | |
153 | ||
154 | header = AV_RL32(buf); | |
155 | version = header & 0xff; | |
156 | header_size = (header & (1<<30))? 8 : 4; /* bit 30 means pad to 8 bytes */ | |
157 | ||
158 | if (version > 5) { | |
159 | av_log(avctx, AV_LOG_ERROR, | |
160 | "This file is encoded with Fraps version %d. " \ | |
161 | "This codec can only decode versions <= 5.\n", version); | |
162 | return AVERROR_PATCHWELCOME; | |
163 | } | |
164 | ||
165 | buf += header_size; | |
166 | ||
167 | if (version < 2) { | |
168 | unsigned needed_size = avctx->width * avctx->height * 3; | |
169 | if (version == 0) needed_size /= 2; | |
170 | needed_size += header_size; | |
171 | /* bit 31 means same as previous pic */ | |
172 | if (header & (1U<<31)) { | |
173 | *got_frame = 0; | |
174 | return buf_size; | |
175 | } | |
176 | if (buf_size != needed_size) { | |
177 | av_log(avctx, AV_LOG_ERROR, | |
178 | "Invalid frame length %d (should be %d)\n", | |
179 | buf_size, needed_size); | |
180 | return AVERROR_INVALIDDATA; | |
181 | } | |
182 | } else { | |
183 | /* skip frame */ | |
184 | if (buf_size == 8) { | |
185 | *got_frame = 0; | |
186 | return buf_size; | |
187 | } | |
188 | if (AV_RL32(buf) != FPS_TAG || buf_size < planes*1024 + 24) { | |
189 | av_log(avctx, AV_LOG_ERROR, "Fraps: error in data stream\n"); | |
190 | return AVERROR_INVALIDDATA; | |
191 | } | |
192 | for (i = 0; i < planes; i++) { | |
193 | offs[i] = AV_RL32(buf + 4 + i * 4); | |
194 | if (offs[i] >= buf_size - header_size || (i && offs[i] <= offs[i - 1] + 1024)) { | |
195 | av_log(avctx, AV_LOG_ERROR, "Fraps: plane %i offset is out of bounds\n", i); | |
196 | return AVERROR_INVALIDDATA; | |
197 | } | |
198 | } | |
199 | offs[planes] = buf_size - header_size; | |
200 | for (i = 0; i < planes; i++) { | |
201 | av_fast_padded_malloc(&s->tmpbuf, &s->tmpbuf_size, offs[i + 1] - offs[i] - 1024); | |
202 | if (!s->tmpbuf) | |
203 | return AVERROR(ENOMEM); | |
204 | } | |
205 | } | |
206 | ||
207 | f->pict_type = AV_PICTURE_TYPE_I; | |
208 | f->key_frame = 1; | |
209 | ||
210 | avctx->pix_fmt = version & 1 ? AV_PIX_FMT_BGR24 : AV_PIX_FMT_YUVJ420P; | |
211 | avctx->color_range = version & 1 ? AVCOL_RANGE_UNSPECIFIED | |
212 | : AVCOL_RANGE_JPEG; | |
213 | avctx->colorspace = version & 1 ? AVCOL_SPC_UNSPECIFIED : AVCOL_SPC_BT709; | |
214 | ||
215 | if ((ret = ff_thread_get_buffer(avctx, &frame, 0)) < 0) | |
216 | return ret; | |
217 | ||
218 | switch (version) { | |
219 | case 0: | |
220 | default: | |
221 | /* Fraps v0 is a reordered YUV420 */ | |
222 | if (((avctx->width % 8) != 0) || ((avctx->height % 2) != 0)) { | |
223 | av_log(avctx, AV_LOG_ERROR, "Invalid frame size %dx%d\n", | |
224 | avctx->width, avctx->height); | |
225 | return AVERROR_INVALIDDATA; | |
226 | } | |
227 | ||
228 | buf32 = (const uint32_t*)buf; | |
229 | for (y = 0; y < avctx->height / 2; y++) { | |
230 | luma1 = (uint32_t*)&f->data[0][ y * 2 * f->linesize[0] ]; | |
231 | luma2 = (uint32_t*)&f->data[0][ (y * 2 + 1) * f->linesize[0] ]; | |
232 | cr = (uint32_t*)&f->data[1][ y * f->linesize[1] ]; | |
233 | cb = (uint32_t*)&f->data[2][ y * f->linesize[2] ]; | |
234 | for (x = 0; x < avctx->width; x += 8) { | |
235 | *luma1++ = *buf32++; | |
236 | *luma1++ = *buf32++; | |
237 | *luma2++ = *buf32++; | |
238 | *luma2++ = *buf32++; | |
239 | *cr++ = *buf32++; | |
240 | *cb++ = *buf32++; | |
241 | } | |
242 | } | |
243 | break; | |
244 | ||
245 | case 1: | |
246 | /* Fraps v1 is an upside-down BGR24 */ | |
247 | for (y = 0; y<avctx->height; y++) | |
248 | memcpy(&f->data[0][(avctx->height - y - 1) * f->linesize[0]], | |
249 | &buf[y * avctx->width * 3], | |
250 | 3 * avctx->width); | |
251 | break; | |
252 | ||
253 | case 2: | |
254 | case 4: | |
255 | /** | |
256 | * Fraps v2 is Huffman-coded YUV420 planes | |
257 | * Fraps v4 is virtually the same | |
258 | */ | |
259 | for (i = 0; i < planes; i++) { | |
260 | is_chroma = !!i; | |
261 | if ((ret = fraps2_decode_plane(s, f->data[i], f->linesize[i], | |
262 | avctx->width >> is_chroma, | |
263 | avctx->height >> is_chroma, | |
264 | buf + offs[i], offs[i + 1] - offs[i], | |
265 | is_chroma, 1)) < 0) { | |
266 | av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); | |
267 | return ret; | |
268 | } | |
269 | } | |
270 | break; | |
271 | case 3: | |
272 | case 5: | |
273 | /* Virtually the same as version 4, but is for RGB24 */ | |
274 | for (i = 0; i < planes; i++) { | |
275 | if ((ret = fraps2_decode_plane(s, f->data[0] + i + (f->linesize[0] * (avctx->height - 1)), | |
276 | -f->linesize[0], avctx->width, avctx->height, | |
277 | buf + offs[i], offs[i + 1] - offs[i], 0, 3)) < 0) { | |
278 | av_log(avctx, AV_LOG_ERROR, "Error decoding plane %i\n", i); | |
279 | return ret; | |
280 | } | |
281 | } | |
282 | out = f->data[0]; | |
283 | // convert pseudo-YUV into real RGB | |
284 | for (j = 0; j < avctx->height; j++) { | |
285 | uint8_t *line_end = out + 3*avctx->width; | |
286 | while (out < line_end) { | |
287 | out[0] += out[1]; | |
288 | out[2] += out[1]; | |
289 | out += 3; | |
290 | } | |
291 | out += f->linesize[0] - 3*avctx->width; | |
292 | } | |
293 | break; | |
294 | } | |
295 | ||
296 | *got_frame = 1; | |
297 | ||
298 | return buf_size; | |
299 | } | |
300 | ||
301 | ||
302 | /** | |
303 | * closes decoder | |
304 | * @param avctx codec context | |
305 | * @return 0 on success or negative if fails | |
306 | */ | |
307 | static av_cold int decode_end(AVCodecContext *avctx) | |
308 | { | |
309 | FrapsContext *s = (FrapsContext*)avctx->priv_data; | |
310 | ||
311 | av_freep(&s->tmpbuf); | |
312 | return 0; | |
313 | } | |
314 | ||
315 | ||
316 | AVCodec ff_fraps_decoder = { | |
317 | .name = "fraps", | |
318 | .long_name = NULL_IF_CONFIG_SMALL("Fraps"), | |
319 | .type = AVMEDIA_TYPE_VIDEO, | |
320 | .id = AV_CODEC_ID_FRAPS, | |
321 | .priv_data_size = sizeof(FrapsContext), | |
322 | .init = decode_init, | |
323 | .close = decode_end, | |
324 | .decode = decode_frame, | |
325 | .capabilities = CODEC_CAP_DR1 | CODEC_CAP_FRAME_THREADS, | |
326 | }; |