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