FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavcodec/smc.c
Date: 2022-07-05 19:52:29
Exec Total Coverage
Lines: 174 220 79.1%
Branches: 102 151 67.5%

Line Branch Exec Source
1 /*
2 * Quicktime Graphics (SMC) Video Decoder
3 * Copyright (C) 2003 The FFmpeg project
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 * QT SMC Video Decoder by Mike Melanson (melanson@pcisys.net)
25 * For more information about the SMC format, visit:
26 * http://www.pcisys.net/~melanson/codecs/
27 *
28 * The SMC decoder outputs PAL8 colorspace data.
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "libavutil/intreadwrite.h"
36 #include "avcodec.h"
37 #include "bytestream.h"
38 #include "codec_internal.h"
39 #include "decode.h"
40 #include "internal.h"
41
42 #define CPAIR 2
43 #define CQUAD 4
44 #define COCTET 8
45
46 #define COLORS_PER_TABLE 256
47
48 typedef struct SmcContext {
49
50 AVCodecContext *avctx;
51 AVFrame *frame;
52
53 GetByteContext gb;
54
55 /* SMC color tables */
56 uint8_t color_pairs[COLORS_PER_TABLE * CPAIR];
57 uint8_t color_quads[COLORS_PER_TABLE * CQUAD];
58 uint8_t color_octets[COLORS_PER_TABLE * COCTET];
59
60 uint32_t pal[256];
61 } SmcContext;
62
63 #define GET_BLOCK_COUNT() \
64 (opcode & 0x10) ? (1 + bytestream2_get_byte(gb)) : 1 + (opcode & 0x0F);
65
66 #define ADVANCE_BLOCK() \
67 { \
68 pixel_ptr += 4; \
69 if (pixel_ptr >= width) \
70 { \
71 pixel_ptr = 0; \
72 row_ptr += stride * 4; \
73 } \
74 total_blocks--; \
75 if (total_blocks < !!n_blocks) \
76 { \
77 av_log(s->avctx, AV_LOG_ERROR, "block counter just went negative (this should not happen)\n"); \
78 return AVERROR_INVALIDDATA; \
79 } \
80 }
81
82 120 static int smc_decode_stream(SmcContext *s)
83 {
84 120 GetByteContext *gb = &s->gb;
85 120 int width = s->avctx->width;
86 120 int height = s->avctx->height;
87 120 int stride = s->frame->linesize[0];
88 int i;
89 int chunk_size;
90 120 int buf_size = bytestream2_size(gb);
91 uint8_t opcode;
92 int n_blocks;
93 unsigned int color_flags;
94 unsigned int color_flags_a;
95 unsigned int color_flags_b;
96 unsigned int flag_mask;
97
98 120 uint8_t * const pixels = s->frame->data[0];
99
100 120 int image_size = height * s->frame->linesize[0];
101 120 int row_ptr = 0;
102 120 int pixel_ptr = 0;
103 int pixel_x, pixel_y;
104 120 int row_inc = stride - 4;
105 int block_ptr;
106 int prev_block_ptr;
107 int prev_block_ptr1, prev_block_ptr2;
108 int prev_block_flag;
109 int total_blocks;
110 int color_table_index; /* indexes to color pair, quad, or octet tables */
111 int pixel;
112
113 120 int color_pair_index = 0;
114 120 int color_quad_index = 0;
115 120 int color_octet_index = 0;
116
117 /* make the palette available */
118 120 memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE);
119
120 120 bytestream2_skip(gb, 1);
121 120 chunk_size = bytestream2_get_be24(gb);
122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (chunk_size != buf_size)
123 av_log(s->avctx, AV_LOG_WARNING, "MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
124 chunk_size, buf_size);
125
126 120 chunk_size = buf_size;
127 120 total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
128
129 /* traverse through the blocks */
130
2/2
✓ Branch 0 taken 130697 times.
✓ Branch 1 taken 120 times.
130817 while (total_blocks) {
131 /* sanity checks */
132 /* make sure the row pointer hasn't gone wild */
133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 130697 times.
130697 if (row_ptr >= image_size) {
134 av_log(s->avctx, AV_LOG_ERROR, "just went out of bounds (row ptr = %d, height = %d)\n",
135 row_ptr, image_size);
136 return AVERROR_INVALIDDATA;
137 }
138
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 130697 times.
130697 if (bytestream2_get_bytes_left(gb) < 1) {
139 av_log(s->avctx, AV_LOG_ERROR, "input too small\n");
140 return AVERROR_INVALIDDATA;
141 }
142
143 130697 opcode = bytestream2_get_byteu(gb);
144
7/9
✓ Branch 0 taken 28630 times.
✓ Branch 1 taken 1068 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11688 times.
✓ Branch 4 taken 17912 times.
✓ Branch 5 taken 35882 times.
✓ Branch 6 taken 33474 times.
✓ Branch 7 taken 2043 times.
✗ Branch 8 not taken.
130697 switch (opcode & 0xF0) {
145 /* skip n blocks */
146 28630 case 0x00:
147 case 0x10:
148
2/2
✓ Branch 0 taken 11959 times.
✓ Branch 1 taken 16671 times.
28630 n_blocks = GET_BLOCK_COUNT();
149
2/2
✓ Branch 0 taken 418385 times.
✓ Branch 1 taken 28630 times.
447015 while (n_blocks--) {
150
3/4
✓ Branch 0 taken 6375 times.
✓ Branch 1 taken 412010 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 418385 times.
418385 ADVANCE_BLOCK();
151 }
152 28630 break;
153
154 /* repeat last block n times */
155 1068 case 0x20:
156 case 0x30:
157
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1057 times.
1068 n_blocks = GET_BLOCK_COUNT();
158
159 /* sanity check */
160
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1068 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1068 if ((row_ptr == 0) && (pixel_ptr == 0)) {
161 av_log(s->avctx, AV_LOG_ERROR, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
162 opcode & 0xF0);
163 return AVERROR_INVALIDDATA;
164 }
165
166 /* figure out where the previous block started */
167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1068 times.
1068 if (pixel_ptr == 0)
168 prev_block_ptr1 =
169 (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
170 else
171 1068 prev_block_ptr1 = row_ptr + pixel_ptr - 4;
172
173
2/2
✓ Branch 0 taken 2325 times.
✓ Branch 1 taken 1068 times.
3393 while (n_blocks--) {
174 2325 block_ptr = row_ptr + pixel_ptr;
175 2325 prev_block_ptr = prev_block_ptr1;
176
2/2
✓ Branch 0 taken 9300 times.
✓ Branch 1 taken 2325 times.
11625 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
177
2/2
✓ Branch 0 taken 37200 times.
✓ Branch 1 taken 9300 times.
46500 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
178 37200 pixels[block_ptr++] = pixels[prev_block_ptr++];
179 }
180 9300 block_ptr += row_inc;
181 9300 prev_block_ptr += row_inc;
182 }
183
3/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 2294 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2325 times.
2325 ADVANCE_BLOCK();
184 }
185 1068 break;
186
187 /* repeat previous pair of blocks n times */
188 case 0x40:
189 case 0x50:
190 n_blocks = GET_BLOCK_COUNT();
191 n_blocks *= 2;
192
193 /* sanity check */
194 if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
195 av_log(s->avctx, AV_LOG_ERROR, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
196 opcode & 0xF0);
197 return AVERROR_INVALIDDATA;
198 }
199
200 /* figure out where the previous 2 blocks started */
201 if (pixel_ptr == 0)
202 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
203 s->avctx->width - 4 * 2;
204 else if (pixel_ptr == 4)
205 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
206 else
207 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
208
209 if (pixel_ptr == 0)
210 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
211 else
212 prev_block_ptr2 = row_ptr + pixel_ptr - 4;
213
214 prev_block_flag = 0;
215 while (n_blocks--) {
216 block_ptr = row_ptr + pixel_ptr;
217 if (prev_block_flag)
218 prev_block_ptr = prev_block_ptr2;
219 else
220 prev_block_ptr = prev_block_ptr1;
221 prev_block_flag = !prev_block_flag;
222
223 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
224 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
225 pixels[block_ptr++] = pixels[prev_block_ptr++];
226 }
227 block_ptr += row_inc;
228 prev_block_ptr += row_inc;
229 }
230 ADVANCE_BLOCK();
231 }
232 break;
233
234 /* 1-color block encoding */
235 11688 case 0x60:
236 case 0x70:
237
2/2
✓ Branch 0 taken 1082 times.
✓ Branch 1 taken 10606 times.
11688 n_blocks = GET_BLOCK_COUNT();
238 11688 pixel = bytestream2_get_byte(gb);
239
240
2/2
✓ Branch 0 taken 50417 times.
✓ Branch 1 taken 11688 times.
62105 while (n_blocks--) {
241 50417 block_ptr = row_ptr + pixel_ptr;
242
2/2
✓ Branch 0 taken 201668 times.
✓ Branch 1 taken 50417 times.
252085 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
243
2/2
✓ Branch 0 taken 806672 times.
✓ Branch 1 taken 201668 times.
1008340 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
244 806672 pixels[block_ptr++] = pixel;
245 }
246 201668 block_ptr += row_inc;
247 }
248
3/4
✓ Branch 0 taken 631 times.
✓ Branch 1 taken 49786 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50417 times.
50417 ADVANCE_BLOCK();
249 }
250 11688 break;
251
252 /* 2-color block encoding */
253 17912 case 0x80:
254 case 0x90:
255 17912 n_blocks = (opcode & 0x0F) + 1;
256
257 /* figure out which color pair to use to paint the 2-color block */
258
2/2
✓ Branch 0 taken 5271 times.
✓ Branch 1 taken 12641 times.
17912 if ((opcode & 0xF0) == 0x80) {
259 /* fetch the next 2 colors from bytestream and store in next
260 * available entry in the color pair table */
261
2/2
✓ Branch 0 taken 10542 times.
✓ Branch 1 taken 5271 times.
15813 for (i = 0; i < CPAIR; i++) {
262 10542 pixel = bytestream2_get_byte(gb);
263 10542 color_table_index = CPAIR * color_pair_index + i;
264 10542 s->color_pairs[color_table_index] = pixel;
265 }
266 /* this is the base index to use for this block */
267 5271 color_table_index = CPAIR * color_pair_index;
268 5271 color_pair_index++;
269 /* wraparound */
270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5271 times.
5271 if (color_pair_index == COLORS_PER_TABLE)
271 color_pair_index = 0;
272 } else
273 12641 color_table_index = CPAIR * bytestream2_get_byte(gb);
274
275
2/2
✓ Branch 0 taken 18944 times.
✓ Branch 1 taken 17912 times.
36856 while (n_blocks--) {
276 18944 color_flags = bytestream2_get_be16(gb);
277 18944 flag_mask = 0x8000;
278 18944 block_ptr = row_ptr + pixel_ptr;
279
2/2
✓ Branch 0 taken 75776 times.
✓ Branch 1 taken 18944 times.
94720 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
280
2/2
✓ Branch 0 taken 303104 times.
✓ Branch 1 taken 75776 times.
378880 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
281
2/2
✓ Branch 0 taken 121822 times.
✓ Branch 1 taken 181282 times.
303104 if (color_flags & flag_mask)
282 121822 pixel = color_table_index + 1;
283 else
284 181282 pixel = color_table_index;
285 303104 flag_mask >>= 1;
286 303104 pixels[block_ptr++] = s->color_pairs[pixel];
287 }
288 75776 block_ptr += row_inc;
289 }
290
3/4
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 18903 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 18944 times.
18944 ADVANCE_BLOCK();
291 }
292 17912 break;
293
294 /* 4-color block encoding */
295 35882 case 0xA0:
296 case 0xB0:
297 35882 n_blocks = (opcode & 0x0F) + 1;
298
299 /* figure out which color quad to use to paint the 4-color block */
300
2/2
✓ Branch 0 taken 14534 times.
✓ Branch 1 taken 21348 times.
35882 if ((opcode & 0xF0) == 0xA0) {
301 /* fetch the next 4 colors from bytestream and store in next
302 * available entry in the color quad table */
303
2/2
✓ Branch 0 taken 58136 times.
✓ Branch 1 taken 14534 times.
72670 for (i = 0; i < CQUAD; i++) {
304 58136 pixel = bytestream2_get_byte(gb);
305 58136 color_table_index = CQUAD * color_quad_index + i;
306 58136 s->color_quads[color_table_index] = pixel;
307 }
308 /* this is the base index to use for this block */
309 14534 color_table_index = CQUAD * color_quad_index;
310 14534 color_quad_index++;
311 /* wraparound */
312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14534 times.
14534 if (color_quad_index == COLORS_PER_TABLE)
313 color_quad_index = 0;
314 } else
315 21348 color_table_index = CQUAD * bytestream2_get_byte(gb);
316
317
2/2
✓ Branch 0 taken 41159 times.
✓ Branch 1 taken 35882 times.
77041 while (n_blocks--) {
318 41159 color_flags = bytestream2_get_be32(gb);
319 /* flag mask actually acts as a bit shift count here */
320 41159 flag_mask = 30;
321 41159 block_ptr = row_ptr + pixel_ptr;
322
2/2
✓ Branch 0 taken 164636 times.
✓ Branch 1 taken 41159 times.
205795 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
323
2/2
✓ Branch 0 taken 658544 times.
✓ Branch 1 taken 164636 times.
823180 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
324 658544 pixel = color_table_index +
325 658544 ((color_flags >> flag_mask) & 0x03);
326 658544 flag_mask -= 2;
327 658544 pixels[block_ptr++] = s->color_quads[pixel];
328 }
329 164636 block_ptr += row_inc;
330 }
331
3/4
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 41081 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 41159 times.
41159 ADVANCE_BLOCK();
332 }
333 35882 break;
334
335 /* 8-color block encoding */
336 33474 case 0xC0:
337 case 0xD0:
338 33474 n_blocks = (opcode & 0x0F) + 1;
339
340 /* figure out which color octet to use to paint the 8-color block */
341
2/2
✓ Branch 0 taken 10987 times.
✓ Branch 1 taken 22487 times.
33474 if ((opcode & 0xF0) == 0xC0) {
342 /* fetch the next 8 colors from bytestream and store in next
343 * available entry in the color octet table */
344
2/2
✓ Branch 0 taken 87896 times.
✓ Branch 1 taken 10987 times.
98883 for (i = 0; i < COCTET; i++) {
345 87896 pixel = bytestream2_get_byte(gb);
346 87896 color_table_index = COCTET * color_octet_index + i;
347 87896 s->color_octets[color_table_index] = pixel;
348 }
349 /* this is the base index to use for this block */
350 10987 color_table_index = COCTET * color_octet_index;
351 10987 color_octet_index++;
352 /* wraparound */
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10987 times.
10987 if (color_octet_index == COLORS_PER_TABLE)
354 color_octet_index = 0;
355 } else
356 22487 color_table_index = COCTET * bytestream2_get_byte(gb);
357
358
2/2
✓ Branch 0 taken 42573 times.
✓ Branch 1 taken 33474 times.
76047 while (n_blocks--) {
359 /*
360 For this input of 6 hex bytes:
361 01 23 45 67 89 AB
362 Mangle it to this output:
363 flags_a = xx012456, flags_b = xx89A37B
364 */
365 /* build the color flags */
366 42573 int val1 = bytestream2_get_be16(gb);
367 42573 int val2 = bytestream2_get_be16(gb);
368 42573 int val3 = bytestream2_get_be16(gb);
369 42573 color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4);
370 42573 color_flags_b = ((val3 & 0xFFF0) << 8) |
371 42573 ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F);
372
373 42573 color_flags = color_flags_a;
374 /* flag mask actually acts as a bit shift count here */
375 42573 flag_mask = 21;
376 42573 block_ptr = row_ptr + pixel_ptr;
377
2/2
✓ Branch 0 taken 170292 times.
✓ Branch 1 taken 42573 times.
212865 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
378 /* reload flags at third row (iteration pixel_y == 2) */
379
2/2
✓ Branch 0 taken 42573 times.
✓ Branch 1 taken 127719 times.
170292 if (pixel_y == 2) {
380 42573 color_flags = color_flags_b;
381 42573 flag_mask = 21;
382 }
383
2/2
✓ Branch 0 taken 681168 times.
✓ Branch 1 taken 170292 times.
851460 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
384 681168 pixel = color_table_index +
385 681168 ((color_flags >> flag_mask) & 0x07);
386 681168 flag_mask -= 3;
387 681168 pixels[block_ptr++] = s->color_octets[pixel];
388 }
389 170292 block_ptr += row_inc;
390 }
391
3/4
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 42529 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42573 times.
42573 ADVANCE_BLOCK();
392 }
393 33474 break;
394
395 /* 16-color block encoding (every pixel is a different color) */
396 2043 case 0xE0:
397 case 0xF0:
398 2043 n_blocks = (opcode & 0x0F) + 1;
399
400
2/2
✓ Branch 0 taken 2197 times.
✓ Branch 1 taken 2043 times.
4240 while (n_blocks--) {
401 2197 block_ptr = row_ptr + pixel_ptr;
402
2/2
✓ Branch 0 taken 8788 times.
✓ Branch 1 taken 2197 times.
10985 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
403
2/2
✓ Branch 0 taken 35152 times.
✓ Branch 1 taken 8788 times.
43940 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
404 35152 pixels[block_ptr++] = bytestream2_get_byte(gb);
405 }
406 8788 block_ptr += row_inc;
407 }
408
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2197 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2197 times.
2197 ADVANCE_BLOCK();
409 }
410 2043 break;
411 }
412 }
413
414 120 return 0;
415 }
416
417 2 static av_cold int smc_decode_init(AVCodecContext *avctx)
418 {
419 2 SmcContext *s = avctx->priv_data;
420
421 2 s->avctx = avctx;
422 2 avctx->pix_fmt = AV_PIX_FMT_PAL8;
423
424 2 s->frame = av_frame_alloc();
425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!s->frame)
426 return AVERROR(ENOMEM);
427
428 2 return 0;
429 }
430
431 120 static int smc_decode_frame(AVCodecContext *avctx, AVFrame *rframe,
432 int *got_frame, AVPacket *avpkt)
433 {
434 120 const uint8_t *buf = avpkt->data;
435 120 int buf_size = avpkt->size;
436 120 SmcContext *s = avctx->priv_data;
437 int ret;
438 120 int total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
439
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (total_blocks / 1024 > avpkt->size)
441 return AVERROR_INVALIDDATA;
442
443 120 bytestream2_init(&s->gb, buf, buf_size);
444
445
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0)
446 return ret;
447
448 120 s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx);
449
450 120 ret = smc_decode_stream(s);
451
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 120 times.
120 if (ret < 0)
452 return ret;
453
454 120 *got_frame = 1;
455
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
120 if ((ret = av_frame_ref(rframe, s->frame)) < 0)
456 return ret;
457
458 /* always report that the buffer was completely consumed */
459 120 return buf_size;
460 }
461
462 2 static av_cold int smc_decode_end(AVCodecContext *avctx)
463 {
464 2 SmcContext *s = avctx->priv_data;
465
466 2 av_frame_free(&s->frame);
467
468 2 return 0;
469 }
470
471 const FFCodec ff_smc_decoder = {
472 .p.name = "smc",
473 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
474 .p.type = AVMEDIA_TYPE_VIDEO,
475 .p.id = AV_CODEC_ID_SMC,
476 .priv_data_size = sizeof(SmcContext),
477 .init = smc_decode_init,
478 .close = smc_decode_end,
479 FF_CODEC_DECODE_CB(smc_decode_frame),
480 .p.capabilities = AV_CODEC_CAP_DR1,
481 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
482 };
483