/src/ffmpeg/libavcodec/tdsc.c
Line | Count | Source |
1 | | /* |
2 | | * TDSC decoder |
3 | | * Copyright (C) 2015 Vittorio Giovara <vittorio.giovara@gmail.com> |
4 | | * |
5 | | * This file is part of FFmpeg. |
6 | | * |
7 | | * FFmpeg is free software; you can redistribute it and/or |
8 | | * modify it under the terms of the GNU Lesser General Public |
9 | | * License as published by the Free Software Foundation; either |
10 | | * version 2.1 of the License, or (at your option) any later version. |
11 | | * |
12 | | * FFmpeg is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
15 | | * Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License along with FFmpeg; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
20 | | */ |
21 | | |
22 | | /** |
23 | | * @file |
24 | | * TDSC decoder |
25 | | * |
26 | | * Fourcc: TSDC |
27 | | * |
28 | | * TDSC is very simple. It codes picture by tiles, storing them in raw BGR24 |
29 | | * format or compressing them in JPEG. Frames can be full pictures or just |
30 | | * updates to the previous frame. Cursor is found in its own frame or at the |
31 | | * bottom of the picture. Every frame is then packed with zlib. |
32 | | * |
33 | | * Supports: BGR24 |
34 | | */ |
35 | | |
36 | | #include <stdint.h> |
37 | | #include <zlib.h> |
38 | | |
39 | | #include "libavutil/attributes_internal.h" |
40 | | #include "libavutil/imgutils.h" |
41 | | #include "libavutil/mem.h" |
42 | | |
43 | | #include "avcodec.h" |
44 | | #include "bytestream.h" |
45 | | #include "codec_internal.h" |
46 | | #include "decode.h" |
47 | | |
48 | 0 | #define BITMAPINFOHEADER_SIZE 0x28 |
49 | 0 | #define TDSF_HEADER_SIZE 0x56 |
50 | 0 | #define TDSB_HEADER_SIZE 0x08 |
51 | | |
52 | | typedef struct TDSCContext { |
53 | | AVCodecContext *jpeg_avctx; // wrapper context for MJPEG |
54 | | |
55 | | int width, height; |
56 | | GetByteContext gbc; |
57 | | |
58 | | AVFrame *refframe; // full decoded frame (without cursor) |
59 | | AVPacket *jpkt; // encoded JPEG tile |
60 | | AVFrame *jpgframe; // decoded JPEG tile |
61 | | uint8_t *tilebuffer; // buffer containing tile data |
62 | | |
63 | | /* zlib interaction */ |
64 | | uint8_t *deflatebuffer; |
65 | | uLongf deflatelen; |
66 | | |
67 | | /* All that is cursor */ |
68 | | uint8_t *cursor; |
69 | | int cursor_stride; |
70 | | int cursor_w, cursor_h, cursor_x, cursor_y; |
71 | | int cursor_hot_x, cursor_hot_y; |
72 | | } TDSCContext; |
73 | | |
74 | | /* 1 byte bits, 1 byte planes, 2 bytes format (probably) */ |
75 | | enum TDSCCursorFormat { |
76 | | CUR_FMT_MONO = 0x01010004, |
77 | | CUR_FMT_BGRA = 0x20010004, |
78 | | CUR_FMT_RGBA = 0x20010008, |
79 | | }; |
80 | | |
81 | | static av_cold int tdsc_close(AVCodecContext *avctx) |
82 | 1.05k | { |
83 | 1.05k | TDSCContext *ctx = avctx->priv_data; |
84 | | |
85 | 1.05k | av_frame_free(&ctx->refframe); |
86 | 1.05k | av_frame_free(&ctx->jpgframe); |
87 | 1.05k | av_packet_free(&ctx->jpkt); |
88 | 1.05k | av_freep(&ctx->deflatebuffer); |
89 | 1.05k | av_freep(&ctx->tilebuffer); |
90 | 1.05k | av_freep(&ctx->cursor); |
91 | 1.05k | avcodec_free_context(&ctx->jpeg_avctx); |
92 | | |
93 | 1.05k | return 0; |
94 | 1.05k | } |
95 | | |
96 | | static av_cold int tdsc_init(AVCodecContext *avctx) |
97 | 1.05k | { |
98 | 1.05k | TDSCContext *ctx = avctx->priv_data; |
99 | 1.05k | int ret; |
100 | | |
101 | 1.05k | avctx->pix_fmt = AV_PIX_FMT_BGR24; |
102 | | |
103 | | /* These needs to be set to estimate buffer and frame size */ |
104 | 1.05k | if (!(avctx->width && avctx->height)) { |
105 | 137 | av_log(avctx, AV_LOG_ERROR, "Video size not set.\n"); |
106 | 137 | return AVERROR_INVALIDDATA; |
107 | 137 | } |
108 | | |
109 | | /* This value should be large enough for a RAW-only frame plus headers */ |
110 | 918 | ctx->deflatelen = avctx->width * avctx->height * (3 + 1); |
111 | 918 | ret = av_reallocp(&ctx->deflatebuffer, ctx->deflatelen); |
112 | 918 | if (ret < 0) |
113 | 0 | return ret; |
114 | | |
115 | | /* Allocate reference and JPEG frame */ |
116 | 918 | ctx->refframe = av_frame_alloc(); |
117 | 918 | ctx->jpgframe = av_frame_alloc(); |
118 | 918 | ctx->jpkt = av_packet_alloc(); |
119 | 918 | if (!ctx->refframe || !ctx->jpgframe || !ctx->jpkt) |
120 | 0 | return AVERROR(ENOMEM); |
121 | | |
122 | | /* Prepare everything needed for JPEG decoding */ |
123 | 918 | EXTERN const FFCodec ff_mjpeg_decoder; |
124 | 918 | ctx->jpeg_avctx = avcodec_alloc_context3(&ff_mjpeg_decoder.p); |
125 | 918 | if (!ctx->jpeg_avctx) |
126 | 0 | return AVERROR(ENOMEM); |
127 | 918 | ctx->jpeg_avctx->flags = avctx->flags; |
128 | 918 | ctx->jpeg_avctx->flags2 = avctx->flags2; |
129 | 918 | ctx->jpeg_avctx->idct_algo = avctx->idct_algo; |
130 | 918 | ret = avcodec_open2(ctx->jpeg_avctx, NULL, NULL); |
131 | 918 | if (ret < 0) |
132 | 0 | return ret; |
133 | | |
134 | | /* Set the output pixel format on the reference frame */ |
135 | 918 | ctx->refframe->format = avctx->pix_fmt; |
136 | | |
137 | 918 | return 0; |
138 | 918 | } |
139 | | |
140 | | #define APPLY_ALPHA(src, new, alpha) \ |
141 | 0 | src = (src * (256 - alpha) + new * alpha) >> 8 |
142 | | |
143 | | /* Paint a region over a buffer, without drawing out of its bounds. */ |
144 | | static void tdsc_paint_cursor(AVCodecContext *avctx, uint8_t *dst, int stride) |
145 | 0 | { |
146 | 0 | TDSCContext *ctx = avctx->priv_data; |
147 | 0 | const uint8_t *cursor = ctx->cursor; |
148 | 0 | int x = ctx->cursor_x - ctx->cursor_hot_x; |
149 | 0 | int y = ctx->cursor_y - ctx->cursor_hot_y; |
150 | 0 | int w = ctx->cursor_w; |
151 | 0 | int h = ctx->cursor_h; |
152 | 0 | int i, j; |
153 | |
|
154 | 0 | if (!ctx->cursor) |
155 | 0 | return; |
156 | | |
157 | 0 | if (x + w > ctx->width) |
158 | 0 | w = ctx->width - x; |
159 | 0 | if (y + h > ctx->height) |
160 | 0 | h = ctx->height - y; |
161 | 0 | if (x < 0) { |
162 | 0 | w += x; |
163 | 0 | cursor += -x * 4; |
164 | 0 | } else { |
165 | 0 | dst += x * 3; |
166 | 0 | } |
167 | 0 | if (y < 0) { |
168 | 0 | h += y; |
169 | 0 | cursor += -y * ctx->cursor_stride; |
170 | 0 | } else { |
171 | 0 | dst += y * stride; |
172 | 0 | } |
173 | 0 | if (w < 0 || h < 0) |
174 | 0 | return; |
175 | | |
176 | 0 | for (j = 0; j < h; j++) { |
177 | 0 | for (i = 0; i < w; i++) { |
178 | 0 | uint8_t alpha = cursor[i * 4]; |
179 | 0 | APPLY_ALPHA(dst[i * 3 + 0], cursor[i * 4 + 1], alpha); |
180 | 0 | APPLY_ALPHA(dst[i * 3 + 1], cursor[i * 4 + 2], alpha); |
181 | 0 | APPLY_ALPHA(dst[i * 3 + 2], cursor[i * 4 + 3], alpha); |
182 | 0 | } |
183 | 0 | dst += stride; |
184 | 0 | cursor += ctx->cursor_stride; |
185 | 0 | } |
186 | 0 | } |
187 | | |
188 | | /* Load cursor data and store it in ABGR mode. */ |
189 | | static int tdsc_load_cursor(AVCodecContext *avctx) |
190 | 0 | { |
191 | 0 | TDSCContext *ctx = avctx->priv_data; |
192 | 0 | int i, j, k, ret, cursor_fmt; |
193 | 0 | uint8_t *dst; |
194 | |
|
195 | 0 | ctx->cursor_hot_x = bytestream2_get_le16(&ctx->gbc); |
196 | 0 | ctx->cursor_hot_y = bytestream2_get_le16(&ctx->gbc); |
197 | 0 | ctx->cursor_w = bytestream2_get_le16(&ctx->gbc); |
198 | 0 | ctx->cursor_h = bytestream2_get_le16(&ctx->gbc); |
199 | |
|
200 | 0 | ctx->cursor_stride = FFALIGN(ctx->cursor_w, 32) * 4; |
201 | 0 | cursor_fmt = bytestream2_get_le32(&ctx->gbc); |
202 | |
|
203 | 0 | if (ctx->cursor_x >= avctx->width || ctx->cursor_y >= avctx->height) { |
204 | 0 | av_log(avctx, AV_LOG_ERROR, |
205 | 0 | "Invalid cursor position (%d.%d outside %dx%d).\n", |
206 | 0 | ctx->cursor_x, ctx->cursor_y, avctx->width, avctx->height); |
207 | 0 | return AVERROR_INVALIDDATA; |
208 | 0 | } |
209 | 0 | if (ctx->cursor_w < 1 || ctx->cursor_w > 256 || |
210 | 0 | ctx->cursor_h < 1 || ctx->cursor_h > 256) { |
211 | 0 | av_log(avctx, AV_LOG_ERROR, |
212 | 0 | "Invalid cursor dimensions %dx%d.\n", |
213 | 0 | ctx->cursor_w, ctx->cursor_h); |
214 | 0 | return AVERROR_INVALIDDATA; |
215 | 0 | } |
216 | 0 | if (ctx->cursor_hot_x > ctx->cursor_w || |
217 | 0 | ctx->cursor_hot_y > ctx->cursor_h) { |
218 | 0 | av_log(avctx, AV_LOG_WARNING, "Invalid hotspot position %d.%d.\n", |
219 | 0 | ctx->cursor_hot_x, ctx->cursor_hot_y); |
220 | 0 | ctx->cursor_hot_x = FFMIN(ctx->cursor_hot_x, ctx->cursor_w - 1); |
221 | 0 | ctx->cursor_hot_y = FFMIN(ctx->cursor_hot_y, ctx->cursor_h - 1); |
222 | 0 | } |
223 | |
|
224 | 0 | ret = av_reallocp(&ctx->cursor, ctx->cursor_stride * ctx->cursor_h); |
225 | 0 | if (ret < 0) { |
226 | 0 | av_log(avctx, AV_LOG_ERROR, "Cannot allocate cursor buffer.\n"); |
227 | 0 | return ret; |
228 | 0 | } |
229 | | |
230 | 0 | dst = ctx->cursor; |
231 | | /* here data is packed in BE */ |
232 | 0 | switch (cursor_fmt) { |
233 | 0 | case CUR_FMT_MONO: |
234 | 0 | for (j = 0; j < ctx->cursor_h; j++) { |
235 | 0 | for (i = 0; i < ctx->cursor_w; i += 32) { |
236 | 0 | uint32_t bits = bytestream2_get_be32(&ctx->gbc); |
237 | 0 | for (k = 0; k < 32; k++) { |
238 | 0 | dst[0] = !!(bits & 0x80000000); |
239 | 0 | dst += 4; |
240 | 0 | bits <<= 1; |
241 | 0 | } |
242 | 0 | } |
243 | 0 | dst += ctx->cursor_stride - ctx->cursor_w * 4; |
244 | 0 | } |
245 | |
|
246 | 0 | dst = ctx->cursor; |
247 | 0 | for (j = 0; j < ctx->cursor_h; j++) { |
248 | 0 | for (i = 0; i < ctx->cursor_w; i += 32) { |
249 | 0 | uint32_t bits = bytestream2_get_be32(&ctx->gbc); |
250 | 0 | for (k = 0; k < 32; k++) { |
251 | 0 | int mask_bit = !!(bits & 0x80000000); |
252 | 0 | switch (dst[0] * 2 + mask_bit) { |
253 | 0 | case 0: |
254 | 0 | dst[0] = 0xFF; |
255 | 0 | dst[1] = 0x00; |
256 | 0 | dst[2] = 0x00; |
257 | 0 | dst[3] = 0x00; |
258 | 0 | break; |
259 | 0 | case 1: |
260 | 0 | dst[0] = 0xFF; |
261 | 0 | dst[1] = 0xFF; |
262 | 0 | dst[2] = 0xFF; |
263 | 0 | dst[3] = 0xFF; |
264 | 0 | break; |
265 | 0 | default: |
266 | 0 | dst[0] = 0x00; |
267 | 0 | dst[1] = 0x00; |
268 | 0 | dst[2] = 0x00; |
269 | 0 | dst[3] = 0x00; |
270 | 0 | } |
271 | 0 | dst += 4; |
272 | 0 | bits <<= 1; |
273 | 0 | } |
274 | 0 | } |
275 | 0 | dst += ctx->cursor_stride - ctx->cursor_w * 4; |
276 | 0 | } |
277 | 0 | break; |
278 | 0 | case CUR_FMT_BGRA: |
279 | 0 | case CUR_FMT_RGBA: |
280 | | /* Skip monochrome version of the cursor */ |
281 | 0 | bytestream2_skip(&ctx->gbc, |
282 | 0 | ctx->cursor_h * (FFALIGN(ctx->cursor_w, 32) >> 3)); |
283 | 0 | if (cursor_fmt & 8) { // RGBA -> ABGR |
284 | 0 | for (j = 0; j < ctx->cursor_h; j++) { |
285 | 0 | for (i = 0; i < ctx->cursor_w; i++) { |
286 | 0 | int val = bytestream2_get_be32(&ctx->gbc); |
287 | 0 | *dst++ = val >> 24; |
288 | 0 | *dst++ = val >> 16; |
289 | 0 | *dst++ = val >> 8; |
290 | 0 | *dst++ = val >> 0; |
291 | 0 | } |
292 | 0 | dst += ctx->cursor_stride - ctx->cursor_w * 4; |
293 | 0 | } |
294 | 0 | } else { // BGRA -> ABGR |
295 | 0 | for (j = 0; j < ctx->cursor_h; j++) { |
296 | 0 | for (i = 0; i < ctx->cursor_w; i++) { |
297 | 0 | int val = bytestream2_get_be32(&ctx->gbc); |
298 | 0 | *dst++ = val >> 0; |
299 | 0 | *dst++ = val >> 24; |
300 | 0 | *dst++ = val >> 16; |
301 | 0 | *dst++ = val >> 8; |
302 | 0 | } |
303 | 0 | dst += ctx->cursor_stride - ctx->cursor_w * 4; |
304 | 0 | } |
305 | 0 | } |
306 | 0 | break; |
307 | 0 | default: |
308 | 0 | avpriv_request_sample(avctx, "Cursor format %08x", cursor_fmt); |
309 | 0 | return AVERROR_PATCHWELCOME; |
310 | 0 | } |
311 | | |
312 | 0 | return 0; |
313 | 0 | } |
314 | | |
315 | | /* Convert a single YUV pixel to RGB. */ |
316 | | static inline void tdsc_yuv2rgb(uint8_t *out, int Y, int U, int V) |
317 | 0 | { |
318 | 0 | out[0] = av_clip_uint8(Y + ( 91881 * V + 32768 >> 16)); |
319 | 0 | out[1] = av_clip_uint8(Y + (-22554 * U - 46802 * V + 32768 >> 16)); |
320 | 0 | out[2] = av_clip_uint8(Y + (116130 * U + 32768 >> 16)); |
321 | 0 | } |
322 | | |
323 | | /* Convert a YUV420 buffer to a RGB buffer. */ |
324 | | static av_always_inline void tdsc_blit(uint8_t *dst, int dst_stride, |
325 | | const uint8_t *srcy, int srcy_stride, |
326 | | const uint8_t *srcu, const uint8_t *srcv, |
327 | | int srcuv_stride, int width, int height) |
328 | 0 | { |
329 | 0 | int col, line; |
330 | 0 | for (line = 0; line < height; line++) { |
331 | 0 | for (col = 0; col < width; col++) |
332 | 0 | tdsc_yuv2rgb(dst + col * 3, srcy[col], |
333 | 0 | srcu[col >> 1] - 128, srcv[col >> 1] - 128); |
334 | |
|
335 | 0 | dst += dst_stride; |
336 | 0 | srcy += srcy_stride; |
337 | 0 | srcu += srcuv_stride * (line & 1); |
338 | 0 | srcv += srcuv_stride * (line & 1); |
339 | 0 | } |
340 | 0 | } |
341 | | |
342 | | /* Invoke the MJPEG decoder to decode the tile. */ |
343 | | static int tdsc_decode_jpeg_tile(AVCodecContext *avctx, int tile_size, |
344 | | int x, int y, int w, int h) |
345 | 0 | { |
346 | 0 | TDSCContext *ctx = avctx->priv_data; |
347 | 0 | int ret; |
348 | | |
349 | | /* Prepare a packet and send to the MJPEG decoder */ |
350 | 0 | av_packet_unref(ctx->jpkt); |
351 | 0 | ctx->jpkt->data = ctx->tilebuffer; |
352 | 0 | ctx->jpkt->size = tile_size; |
353 | |
|
354 | 0 | ret = avcodec_send_packet(ctx->jpeg_avctx, ctx->jpkt); |
355 | 0 | if (ret < 0) { |
356 | 0 | av_log(avctx, AV_LOG_ERROR, "Error submitting a packet for decoding\n"); |
357 | 0 | return ret; |
358 | 0 | } |
359 | | |
360 | 0 | ret = avcodec_receive_frame(ctx->jpeg_avctx, ctx->jpgframe); |
361 | 0 | if (ret < 0 || ctx->jpgframe->format != AV_PIX_FMT_YUVJ420P) { |
362 | 0 | av_log(avctx, AV_LOG_ERROR, |
363 | 0 | "JPEG decoding error (%d).\n", ret); |
364 | | |
365 | | /* Normally skip, error if explode */ |
366 | 0 | if (avctx->err_recognition & AV_EF_EXPLODE) |
367 | 0 | return AVERROR_INVALIDDATA; |
368 | 0 | else |
369 | 0 | return 0; |
370 | 0 | } |
371 | | |
372 | | /* Let's paint onto the buffer */ |
373 | 0 | tdsc_blit(ctx->refframe->data[0] + x * 3 + ctx->refframe->linesize[0] * y, |
374 | 0 | ctx->refframe->linesize[0], |
375 | 0 | ctx->jpgframe->data[0], ctx->jpgframe->linesize[0], |
376 | 0 | ctx->jpgframe->data[1], ctx->jpgframe->data[2], |
377 | 0 | ctx->jpgframe->linesize[1], w, h); |
378 | |
|
379 | 0 | av_frame_unref(ctx->jpgframe); |
380 | |
|
381 | 0 | return 0; |
382 | 0 | } |
383 | | |
384 | | /* Parse frame and either copy data or decode JPEG. */ |
385 | | static int tdsc_decode_tiles(AVCodecContext *avctx, int number_tiles) |
386 | 0 | { |
387 | 0 | TDSCContext *ctx = avctx->priv_data; |
388 | 0 | int i; |
389 | | |
390 | | /* Iterate over the number of tiles */ |
391 | 0 | for (i = 0; i < number_tiles; i++) { |
392 | 0 | int tile_size; |
393 | 0 | int tile_mode; |
394 | 0 | int x, y, x2, y2, w, h; |
395 | 0 | int ret; |
396 | |
|
397 | 0 | if (bytestream2_get_bytes_left(&ctx->gbc) < 4 || |
398 | 0 | bytestream2_get_le32(&ctx->gbc) != MKTAG('T','D','S','B') || |
399 | 0 | bytestream2_get_bytes_left(&ctx->gbc) < TDSB_HEADER_SIZE - 4) { |
400 | 0 | av_log(avctx, AV_LOG_ERROR, "TDSB tag is too small.\n"); |
401 | 0 | return AVERROR_INVALIDDATA; |
402 | 0 | } |
403 | | |
404 | 0 | tile_size = bytestream2_get_le32(&ctx->gbc); |
405 | 0 | if (bytestream2_get_bytes_left(&ctx->gbc) < tile_size) |
406 | 0 | return AVERROR_INVALIDDATA; |
407 | | |
408 | 0 | tile_mode = bytestream2_get_le32(&ctx->gbc); |
409 | 0 | bytestream2_skip(&ctx->gbc, 4); // unknown |
410 | 0 | x = bytestream2_get_le32(&ctx->gbc); |
411 | 0 | y = bytestream2_get_le32(&ctx->gbc); |
412 | 0 | x2 = bytestream2_get_le32(&ctx->gbc); |
413 | 0 | y2 = bytestream2_get_le32(&ctx->gbc); |
414 | |
|
415 | 0 | if (x < 0 || y < 0 || x2 <= x || y2 <= y || |
416 | 0 | x2 > ctx->width || y2 > ctx->height |
417 | 0 | ) { |
418 | 0 | av_log(avctx, AV_LOG_ERROR, |
419 | 0 | "Invalid tile position (%d.%d %d.%d outside %dx%d).\n", |
420 | 0 | x, y, x2, y2, ctx->width, ctx->height); |
421 | 0 | return AVERROR_INVALIDDATA; |
422 | 0 | } |
423 | 0 | w = x2 - x; |
424 | 0 | h = y2 - y; |
425 | |
|
426 | 0 | ret = av_reallocp(&ctx->tilebuffer, tile_size); |
427 | 0 | if (!ctx->tilebuffer) |
428 | 0 | return ret; |
429 | | |
430 | 0 | bytestream2_get_buffer(&ctx->gbc, ctx->tilebuffer, tile_size); |
431 | |
|
432 | 0 | if (tile_mode == MKTAG('G','E','P','J')) { |
433 | | /* Decode JPEG tile and copy it in the reference frame */ |
434 | 0 | ret = tdsc_decode_jpeg_tile(avctx, tile_size, x, y, w, h); |
435 | 0 | if (ret < 0) |
436 | 0 | return ret; |
437 | 0 | } else if (tile_mode == MKTAG(' ','W','A','R')) { |
438 | | /* Just copy the buffer to output */ |
439 | 0 | av_image_copy_plane(ctx->refframe->data[0] + x * 3 + |
440 | 0 | ctx->refframe->linesize[0] * y, |
441 | 0 | ctx->refframe->linesize[0], ctx->tilebuffer, |
442 | 0 | w * 3, w * 3, h); |
443 | 0 | } else { |
444 | 0 | av_log(avctx, AV_LOG_ERROR, "Unknown tile type %08x.\n", tile_mode); |
445 | 0 | return AVERROR_INVALIDDATA; |
446 | 0 | } |
447 | 0 | av_log(avctx, AV_LOG_DEBUG, "Tile %d, %dx%d (%d.%d)\n", i, w, h, x, y); |
448 | 0 | } |
449 | | |
450 | 0 | return 0; |
451 | 0 | } |
452 | | |
453 | | static int tdsc_parse_tdsf(AVCodecContext *avctx, int number_tiles) |
454 | 0 | { |
455 | 0 | TDSCContext *ctx = avctx->priv_data; |
456 | 0 | int ret, w, h, init_refframe = !ctx->refframe->data[0]; |
457 | | |
458 | | /* BITMAPINFOHEADER |
459 | | * http://msdn.microsoft.com/en-us/library/windows/desktop/dd183376.aspx */ |
460 | 0 | if (bytestream2_get_le32(&ctx->gbc) != BITMAPINFOHEADER_SIZE) |
461 | 0 | return AVERROR_INVALIDDATA; |
462 | | |
463 | | /* Store size, but wait for context reinit before updating avctx */ |
464 | 0 | w = bytestream2_get_le32(&ctx->gbc); |
465 | 0 | h = -bytestream2_get_le32(&ctx->gbc); |
466 | |
|
467 | 0 | if (bytestream2_get_le16(&ctx->gbc) != 1 || // 1 plane |
468 | 0 | bytestream2_get_le16(&ctx->gbc) != 24) // BGR24 |
469 | 0 | return AVERROR_INVALIDDATA; |
470 | | |
471 | 0 | bytestream2_skip(&ctx->gbc, 24); // unused fields |
472 | | |
473 | | /* Update sizes */ |
474 | 0 | if (avctx->width != w || avctx->height != h) { |
475 | 0 | av_log(avctx, AV_LOG_DEBUG, "Size update %dx%d -> %d%d.\n", |
476 | 0 | avctx->width, avctx->height, ctx->width, ctx->height); |
477 | 0 | ret = ff_set_dimensions(avctx, w, h); |
478 | 0 | if (ret < 0) |
479 | 0 | return ret; |
480 | 0 | init_refframe = 1; |
481 | 0 | } |
482 | 0 | ctx->refframe->width = ctx->width = w; |
483 | 0 | ctx->refframe->height = ctx->height = h; |
484 | | |
485 | | /* Allocate the reference frame if not already done or on size change */ |
486 | 0 | if (init_refframe) { |
487 | 0 | ret = av_frame_get_buffer(ctx->refframe, 0); |
488 | 0 | if (ret < 0) |
489 | 0 | return ret; |
490 | 0 | } |
491 | | |
492 | | /* Decode all tiles in a frame */ |
493 | 0 | return tdsc_decode_tiles(avctx, number_tiles); |
494 | 0 | } |
495 | | |
496 | | static int tdsc_parse_dtsm(AVCodecContext *avctx) |
497 | 0 | { |
498 | 0 | TDSCContext *ctx = avctx->priv_data; |
499 | 0 | int ret; |
500 | 0 | int action = bytestream2_get_le32(&ctx->gbc); |
501 | |
|
502 | 0 | bytestream2_skip(&ctx->gbc, 4); // some kind of ID or version maybe? |
503 | |
|
504 | 0 | if (action == 2 || action == 3) { |
505 | | /* Load cursor coordinates */ |
506 | 0 | ctx->cursor_x = bytestream2_get_le32(&ctx->gbc); |
507 | 0 | ctx->cursor_y = bytestream2_get_le32(&ctx->gbc); |
508 | | |
509 | | /* Load a full cursor sprite */ |
510 | 0 | if (action == 3) { |
511 | 0 | ret = tdsc_load_cursor(avctx); |
512 | | /* Do not consider cursor errors fatal unless in explode mode */ |
513 | 0 | if (ret < 0 && (avctx->err_recognition & AV_EF_EXPLODE)) |
514 | 0 | return ret; |
515 | 0 | } |
516 | 0 | } else { |
517 | 0 | avpriv_request_sample(avctx, "Cursor action %d", action); |
518 | 0 | } |
519 | | |
520 | 0 | return 0; |
521 | 0 | } |
522 | | |
523 | | static int tdsc_decode_frame(AVCodecContext *avctx, AVFrame *frame, |
524 | | int *got_frame, AVPacket *avpkt) |
525 | 55.1k | { |
526 | 55.1k | TDSCContext *ctx = avctx->priv_data; |
527 | 55.1k | int ret, tag_header, keyframe = 0; |
528 | 55.1k | uLongf dlen; |
529 | | |
530 | | /* Resize deflate buffer on resolution change */ |
531 | 55.1k | if (ctx->width != avctx->width || ctx->height != avctx->height) { |
532 | 55.1k | int deflatelen = avctx->width * avctx->height * (3 + 1); |
533 | 55.1k | if (deflatelen != ctx->deflatelen) { |
534 | 0 | ctx->deflatelen =deflatelen; |
535 | 0 | ret = av_reallocp(&ctx->deflatebuffer, ctx->deflatelen); |
536 | 0 | if (ret < 0) { |
537 | 0 | ctx->deflatelen = 0; |
538 | 0 | return ret; |
539 | 0 | } |
540 | 0 | } |
541 | 55.1k | } |
542 | 55.1k | dlen = ctx->deflatelen; |
543 | | |
544 | | /* Frames are deflated, need to inflate them first */ |
545 | 55.1k | ret = uncompress(ctx->deflatebuffer, &dlen, avpkt->data, avpkt->size); |
546 | 55.1k | if (ret) { |
547 | 39.4k | av_log(avctx, AV_LOG_ERROR, "Deflate error %d.\n", ret); |
548 | 39.4k | return AVERROR_UNKNOWN; |
549 | 39.4k | } |
550 | | |
551 | 15.7k | bytestream2_init(&ctx->gbc, ctx->deflatebuffer, dlen); |
552 | | |
553 | | /* Check for tag and for size info */ |
554 | 15.7k | if (bytestream2_get_bytes_left(&ctx->gbc) < 4 + 4) { |
555 | 9.02k | av_log(avctx, AV_LOG_ERROR, "Frame is too small.\n"); |
556 | 9.02k | return AVERROR_INVALIDDATA; |
557 | 9.02k | } |
558 | | |
559 | | /* Read tag */ |
560 | 6.68k | tag_header = bytestream2_get_le32(&ctx->gbc); |
561 | | |
562 | 6.68k | if (tag_header == MKTAG('T','D','S','F')) { |
563 | 0 | int number_tiles; |
564 | 0 | if (bytestream2_get_bytes_left(&ctx->gbc) < TDSF_HEADER_SIZE) { |
565 | 0 | av_log(avctx, AV_LOG_ERROR, "TDSF tag is too small.\n"); |
566 | 0 | return AVERROR_INVALIDDATA; |
567 | 0 | } |
568 | | /* First 4 bytes here are the number of GEPJ/WAR tiles in this frame */ |
569 | 0 | number_tiles = bytestream2_get_le32(&ctx->gbc); |
570 | |
|
571 | 0 | bytestream2_skip(&ctx->gbc, 4); // internal timestamp maybe? |
572 | 0 | keyframe = bytestream2_get_le32(&ctx->gbc) == 0x30; |
573 | |
|
574 | 0 | ret = tdsc_parse_tdsf(avctx, number_tiles); |
575 | 0 | if (ret < 0) |
576 | 0 | return ret; |
577 | | |
578 | | /* Check if there is anything else we are able to parse */ |
579 | 0 | if (bytestream2_get_bytes_left(&ctx->gbc) >= 4 + 4) |
580 | 0 | tag_header = bytestream2_get_le32(&ctx->gbc); |
581 | 0 | } |
582 | | |
583 | | /* This tag can be after a TDSF block or on its own frame */ |
584 | 6.68k | if (tag_header == MKTAG('D','T','S','M')) { |
585 | | /* First 4 bytes here are the total size in bytes for this frame */ |
586 | 0 | int tag_size = bytestream2_get_le32(&ctx->gbc); |
587 | |
|
588 | 0 | if (bytestream2_get_bytes_left(&ctx->gbc) < tag_size) { |
589 | 0 | av_log(avctx, AV_LOG_ERROR, "DTSM tag is too small.\n"); |
590 | 0 | return AVERROR_INVALIDDATA; |
591 | 0 | } |
592 | | |
593 | 0 | ret = tdsc_parse_dtsm(avctx); |
594 | 0 | if (ret < 0) |
595 | 0 | return ret; |
596 | 0 | } |
597 | | |
598 | | /* Get the output frame and copy the reference frame */ |
599 | 6.68k | ret = ff_get_buffer(avctx, frame, 0); |
600 | 6.68k | if (ret < 0) |
601 | 264 | return ret; |
602 | | |
603 | 6.42k | ret = av_frame_copy(frame, ctx->refframe); |
604 | 6.42k | if (ret < 0) |
605 | 6.42k | return ret; |
606 | | |
607 | | /* Paint the cursor on the output frame */ |
608 | 0 | tdsc_paint_cursor(avctx, frame->data[0], frame->linesize[0]); |
609 | | |
610 | | /* Frame is ready to be output */ |
611 | 0 | if (keyframe) { |
612 | 0 | frame->pict_type = AV_PICTURE_TYPE_I; |
613 | 0 | frame->flags |= AV_FRAME_FLAG_KEY; |
614 | 0 | } else { |
615 | 0 | frame->pict_type = AV_PICTURE_TYPE_P; |
616 | 0 | } |
617 | 0 | *got_frame = 1; |
618 | |
|
619 | 0 | return avpkt->size; |
620 | 6.42k | } |
621 | | |
622 | | const FFCodec ff_tdsc_decoder = { |
623 | | .p.name = "tdsc", |
624 | | CODEC_LONG_NAME("TDSC"), |
625 | | .p.type = AVMEDIA_TYPE_VIDEO, |
626 | | .p.id = AV_CODEC_ID_TDSC, |
627 | | .init = tdsc_init, |
628 | | FF_CODEC_DECODE_CB(tdsc_decode_frame), |
629 | | .close = tdsc_close, |
630 | | .priv_data_size = sizeof(TDSCContext), |
631 | | .p.capabilities = AV_CODEC_CAP_DR1, |
632 | | .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, |
633 | | }; |