1 /*
2 * QuickTime Graphics (SMC) Video Encoder
3 * Copyright (c) 2021 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 smcenc.c
24 * QT SMC Video Encoder by Paul B. Mahol
25 */
26
27 #include "libavutil/common.h"
28
29 #include "avcodec.h"
30 #include "codec_internal.h"
31 #include "encode.h"
32 #include "bytestream.h"
33
34 #define CPAIR 2
35 #define CQUAD 4
36 #define COCTET 8
37
38 #define COLORS_PER_TABLE 256
39
40 typedef struct SMCContext {
41 AVFrame *prev_frame; // buffer for previous source frame
42
43 uint8_t mono_value;
44 int nb_distinct;
45 int next_nb_distinct;
46 uint8_t distinct_values[16];
47 uint8_t next_distinct_values[16];
48
49 uint8_t color_pairs[COLORS_PER_TABLE][CPAIR];
50 uint8_t color_quads[COLORS_PER_TABLE][CQUAD];
51 uint8_t color_octets[COLORS_PER_TABLE][COCTET];
52
53 int key_frame;
54 } SMCContext;
55
56 #define ADVANCE_BLOCK(pixel_ptr, row_ptr, nb_blocks) \
57 { \
58 for (int block = 0; block < nb_blocks && pixel_ptr && row_ptr; block++) { \
59 pixel_ptr += 4; \
60 if (pixel_ptr - row_ptr >= width) \
61 { \
62 row_ptr += stride * 4; \
63 pixel_ptr = row_ptr; \
64 cur_y += 4; \
65 } \
66 } \
67 }
68
smc_cmp_values(const void *a, const void *b)69 static int smc_cmp_values(const void *a, const void *b)
70 {
71 const uint8_t *aa = a, *bb = b;
72
73 return FFDIFFSIGN(aa[0], bb[0]);
74 }
75
count_distinct_items(const uint8_t *block_values, uint8_t *distinct_values, int size)76 static int count_distinct_items(const uint8_t *block_values,
77 uint8_t *distinct_values,
78 int size)
79 {
80 int n = 1;
81
82 distinct_values[0] = block_values[0];
83 for (int i = 1; i < size; i++) {
84 if (block_values[i] != block_values[i-1]) {
85 distinct_values[n] = block_values[i];
86 n++;
87 }
88 }
89
90 return n;
91 }
92
93 #define CACHE_PAIR(x) \
94 (s->color_pairs[i][0] == distinct_values[x] || \
95 s->color_pairs[i][1] == distinct_values[x])
96
97 #define CACHE_QUAD(x) \
98 (s->color_quads[i][0] == distinct_values[x] || \
99 s->color_quads[i][1] == distinct_values[x] || \
100 s->color_quads[i][2] == distinct_values[x] || \
101 s->color_quads[i][3] == distinct_values[x])
102
103 #define CACHE_OCTET(x) \
104 (s->color_octets[i][0] == distinct_values[x] || \
105 s->color_octets[i][1] == distinct_values[x] || \
106 s->color_octets[i][2] == distinct_values[x] || \
107 s->color_octets[i][3] == distinct_values[x] || \
108 s->color_octets[i][4] == distinct_values[x] || \
109 s->color_octets[i][5] == distinct_values[x] || \
110 s->color_octets[i][6] == distinct_values[x] || \
111 s->color_octets[i][7] == distinct_values[x])
112
smc_encode_stream(SMCContext *s, const AVFrame *frame, PutByteContext *pb)113 static void smc_encode_stream(SMCContext *s, const AVFrame *frame,
114 PutByteContext *pb)
115 {
116 const uint8_t *src_pixels = (const uint8_t *)frame->data[0];
117 const int stride = frame->linesize[0];
118 const uint8_t *prev_pixels = (const uint8_t *)s->prev_frame->data[0];
119 uint8_t *distinct_values = s->distinct_values;
120 const uint8_t *pixel_ptr, *row_ptr;
121 const int height = frame->height;
122 const int width = frame->width;
123 uint8_t block_values[16];
124 int block_counter = 0;
125 int color_pair_index = 0;
126 int color_quad_index = 0;
127 int color_octet_index = 0;
128 int color_table_index; /* indexes to color pair, quad, or octet tables */
129 int total_blocks;
130 int cur_y = 0;
131
132 memset(s->color_pairs, 0, sizeof(s->color_pairs));
133 memset(s->color_quads, 0, sizeof(s->color_quads));
134 memset(s->color_octets, 0, sizeof(s->color_octets));
135
136 /* Number of 4x4 blocks in frame. */
137 total_blocks = ((width + 3) / 4) * ((height + 3) / 4);
138
139 pixel_ptr = row_ptr = src_pixels;
140
141 while (block_counter < total_blocks) {
142 const uint8_t *xpixel_ptr = pixel_ptr;
143 const uint8_t *xrow_ptr = row_ptr;
144 int intra_skip_blocks = 0;
145 int inter_skip_blocks = 0;
146 int coded_distinct = 0;
147 int coded_blocks = 0;
148 int cache_index;
149 int distinct = 0;
150 int blocks = 0;
151 int frame_y = cur_y;
152
153 while (prev_pixels && s->key_frame == 0 && block_counter + inter_skip_blocks < total_blocks) {
154 const int y_size = FFMIN(4, height - cur_y);
155 int compare = 0;
156
157 for (int y = 0; y < y_size; y++) {
158 const ptrdiff_t offset = pixel_ptr - src_pixels;
159 const uint8_t *prev_pixel_ptr = prev_pixels + offset;
160
161 compare |= memcmp(prev_pixel_ptr + y * stride, pixel_ptr + y * stride, 4);
162 if (compare)
163 break;
164 }
165
166 if (compare)
167 break;
168
169 if (inter_skip_blocks >= 256)
170 break;
171 inter_skip_blocks++;
172
173 ADVANCE_BLOCK(pixel_ptr, row_ptr, 1)
174 }
175
176 pixel_ptr = xpixel_ptr;
177 row_ptr = xrow_ptr;
178 cur_y = frame_y;
179
180 while (block_counter > 0 && block_counter + intra_skip_blocks < total_blocks) {
181 const int y_size = FFMIN(4, height - cur_y);
182 const ptrdiff_t offset = pixel_ptr - src_pixels;
183 const int sy = offset / stride;
184 const int sx = offset % stride;
185 const int ny = sx < 4 ? sy - 4 : sy;
186 const int nx = sx < 4 ? width - 4 : sx - 4;
187 const uint8_t *old_pixel_ptr = src_pixels + nx + ny * stride;
188 int compare = 0;
189
190 for (int y = 0; y < y_size; y++) {
191 compare |= memcmp(old_pixel_ptr + y * stride, pixel_ptr + y * stride, 4);
192 if (compare)
193 break;
194 }
195
196 if (compare)
197 break;
198
199 if (intra_skip_blocks >= 256)
200 break;
201 intra_skip_blocks++;
202 ADVANCE_BLOCK(pixel_ptr, row_ptr, 1)
203 }
204
205 pixel_ptr = xpixel_ptr;
206 row_ptr = xrow_ptr;
207 cur_y = frame_y;
208
209 while (block_counter + coded_blocks < total_blocks && coded_blocks < 256) {
210 const int y_size = FFMIN(4, height - cur_y);
211 for (int y = 0; y < y_size; y++)
212 memcpy(block_values + y * 4, pixel_ptr + y * stride, 4);
213
214 qsort(block_values, 16, sizeof(block_values[0]), smc_cmp_values);
215 s->next_nb_distinct = count_distinct_items(block_values, s->next_distinct_values, 16);
216 if (coded_blocks == 0) {
217 memcpy(distinct_values, s->next_distinct_values, sizeof(s->distinct_values));
218 s->nb_distinct = s->next_nb_distinct;
219 } else {
220 if (s->next_nb_distinct != s->nb_distinct ||
221 memcmp(distinct_values, s->next_distinct_values, s->nb_distinct)) {
222 break;
223 }
224 }
225 s->mono_value = block_values[0];
226
227 coded_distinct = s->nb_distinct;
228 ADVANCE_BLOCK(pixel_ptr, row_ptr, 1)
229 coded_blocks++;
230 if (coded_distinct > 1 && coded_blocks >= 16)
231 break;
232 }
233
234 pixel_ptr = xpixel_ptr;
235 row_ptr = xrow_ptr;
236 cur_y = frame_y;
237
238 blocks = coded_blocks;
239 distinct = coded_distinct;
240
241 if (intra_skip_blocks > 0 && intra_skip_blocks >= inter_skip_blocks &&
242 intra_skip_blocks > 0) {
243 distinct = 17;
244 blocks = intra_skip_blocks;
245 }
246
247 if (intra_skip_blocks > 16 && intra_skip_blocks >= inter_skip_blocks &&
248 intra_skip_blocks > 0) {
249 distinct = 18;
250 blocks = intra_skip_blocks;
251 }
252
253 if (inter_skip_blocks > 0 && inter_skip_blocks > intra_skip_blocks &&
254 inter_skip_blocks > 0) {
255 distinct = 19;
256 blocks = inter_skip_blocks;
257 }
258
259 if (inter_skip_blocks > 16 && inter_skip_blocks > intra_skip_blocks &&
260 inter_skip_blocks > 0) {
261 distinct = 20;
262 blocks = inter_skip_blocks;
263 }
264
265 switch (distinct) {
266 case 1:
267 if (blocks <= 16) {
268 bytestream2_put_byte(pb, 0x60 | (blocks - 1));
269 } else {
270 bytestream2_put_byte(pb, 0x70);
271 bytestream2_put_byte(pb, blocks - 1);
272 }
273 bytestream2_put_byte(pb, s->mono_value);
274 ADVANCE_BLOCK(pixel_ptr, row_ptr, blocks)
275 break;
276 case 2:
277 cache_index = -1;
278 for (int i = 0; i < COLORS_PER_TABLE; i++) {
279 if (CACHE_PAIR(0) &&
280 CACHE_PAIR(1)) {
281 cache_index = i;
282 break;
283 }
284 }
285
286 if (cache_index >= 0) {
287 bytestream2_put_byte(pb, 0x90 | (blocks - 1));
288 bytestream2_put_byte(pb, cache_index);
289 color_table_index = cache_index;
290 } else {
291 bytestream2_put_byte(pb, 0x80 | (blocks - 1));
292
293 color_table_index = color_pair_index;
294 for (int i = 0; i < CPAIR; i++) {
295 s->color_pairs[color_table_index][i] = distinct_values[i];
296 bytestream2_put_byte(pb, distinct_values[i]);
297 }
298
299 color_pair_index++;
300 if (color_pair_index == COLORS_PER_TABLE)
301 color_pair_index = 0;
302 }
303
304 for (int i = 0; i < blocks; i++) {
305 uint8_t value = s->color_pairs[color_table_index][1];
306 uint16_t flags = 0;
307 int shift = 15;
308
309 for (int y = 0; y < 4; y++) {
310 for (int x = 0; x < 4; x++) {
311 flags |= (value == pixel_ptr[x + y * stride]) << shift;
312 shift--;
313 }
314 }
315
316 bytestream2_put_be16(pb, flags);
317
318 ADVANCE_BLOCK(pixel_ptr, row_ptr, 1)
319 }
320 break;
321 case 3:
322 case 4:
323 cache_index = -1;
324 for (int i = 0; i < COLORS_PER_TABLE; i++) {
325 if (CACHE_QUAD(0) &&
326 CACHE_QUAD(1) &&
327 CACHE_QUAD(2) &&
328 CACHE_QUAD(3)) {
329 cache_index = i;
330 break;
331 }
332 }
333
334 if (cache_index >= 0) {
335 bytestream2_put_byte(pb, 0xB0 | (blocks - 1));
336 bytestream2_put_byte(pb, cache_index);
337 color_table_index = cache_index;
338 } else {
339 bytestream2_put_byte(pb, 0xA0 | (blocks - 1));
340
341 color_table_index = color_quad_index;
342 for (int i = 0; i < CQUAD; i++) {
343 s->color_quads[color_table_index][i] = distinct_values[i];
344 bytestream2_put_byte(pb, distinct_values[i]);
345 }
346
347 color_quad_index++;
348 if (color_quad_index == COLORS_PER_TABLE)
349 color_quad_index = 0;
350 }
351
352 for (int i = 0; i < blocks; i++) {
353 uint32_t flags = 0;
354 uint8_t quad[4];
355 int shift = 30;
356
357 for (int k = 0; k < 4; k++)
358 quad[k] = s->color_quads[color_table_index][k];
359
360 for (int y = 0; y < 4; y++) {
361 for (int x = 0; x < 4; x++) {
362 int pixel = pixel_ptr[x + y * stride];
363 uint32_t idx = 0;
364
365 for (int w = 0; w < CQUAD; w++) {
366 if (quad[w] == pixel) {
367 idx = w;
368 break;
369 }
370 }
371
372 flags |= idx << shift;
373 shift -= 2;
374 }
375 }
376
377 bytestream2_put_be32(pb, flags);
378
379 ADVANCE_BLOCK(pixel_ptr, row_ptr, 1)
380 }
381 break;
382 case 5:
383 case 6:
384 case 7:
385 case 8:
386 cache_index = -1;
387 for (int i = 0; i < COLORS_PER_TABLE; i++) {
388 if (CACHE_OCTET(0) &&
389 CACHE_OCTET(1) &&
390 CACHE_OCTET(2) &&
391 CACHE_OCTET(3) &&
392 CACHE_OCTET(4) &&
393 CACHE_OCTET(5) &&
394 CACHE_OCTET(6) &&
395 CACHE_OCTET(7)) {
396 cache_index = i;
397 break;
398 }
399 }
400
401 if (cache_index >= 0) {
402 bytestream2_put_byte(pb, 0xD0 | (blocks - 1));
403 bytestream2_put_byte(pb, cache_index);
404 color_table_index = cache_index;
405 } else {
406 bytestream2_put_byte(pb, 0xC0 | (blocks - 1));
407
408 color_table_index = color_octet_index;
409 for (int i = 0; i < COCTET; i++) {
410 s->color_octets[color_table_index][i] = distinct_values[i];
411 bytestream2_put_byte(pb, distinct_values[i]);
412 }
413
414 color_octet_index++;
415 if (color_octet_index == COLORS_PER_TABLE)
416 color_octet_index = 0;
417 }
418
419 for (int i = 0; i < blocks; i++) {
420 uint64_t flags = 0;
421 uint8_t octet[8];
422 int shift = 45;
423
424 for (int k = 0; k < 8; k++)
425 octet[k] = s->color_octets[color_table_index][k];
426
427 for (int y = 0; y < 4; y++) {
428 for (int x = 0; x < 4; x++) {
429 int pixel = pixel_ptr[x + y * stride];
430 uint64_t idx = 0;
431
432 for (int w = 0; w < COCTET; w++) {
433 if (octet[w] == pixel) {
434 idx = w;
435 break;
436 }
437 }
438
439 flags |= idx << shift;
440 shift -= 3;
441 }
442 }
443
444 bytestream2_put_be16(pb, ((flags >> 32) & 0xFFF0) | ((flags >> 8) & 0xF));
445 bytestream2_put_be16(pb, ((flags >> 20) & 0xFFF0) | ((flags >> 4) & 0xF));
446 bytestream2_put_be16(pb, ((flags >> 8) & 0xFFF0) | ((flags >> 0) & 0xF));
447
448 ADVANCE_BLOCK(pixel_ptr, row_ptr, 1)
449 }
450 break;
451 default:
452 bytestream2_put_byte(pb, 0xE0 | (blocks - 1));
453 for (int i = 0; i < blocks; i++) {
454 for (int y = 0; y < 4; y++) {
455 for (int x = 0; x < 4; x++)
456 bytestream2_put_byte(pb, pixel_ptr[x + y * stride]);
457 }
458
459 ADVANCE_BLOCK(pixel_ptr, row_ptr, 1)
460 }
461 break;
462 case 17:
463 bytestream2_put_byte(pb, 0x20 | (blocks - 1));
464 ADVANCE_BLOCK(pixel_ptr, row_ptr, blocks)
465 break;
466 case 18:
467 bytestream2_put_byte(pb, 0x30);
468 bytestream2_put_byte(pb, blocks - 1);
469 ADVANCE_BLOCK(pixel_ptr, row_ptr, blocks)
470 break;
471 case 19:
472 bytestream2_put_byte(pb, 0x00 | (blocks - 1));
473 ADVANCE_BLOCK(pixel_ptr, row_ptr, blocks)
474 break;
475 case 20:
476 bytestream2_put_byte(pb, 0x10);
477 bytestream2_put_byte(pb, blocks - 1);
478 ADVANCE_BLOCK(pixel_ptr, row_ptr, blocks)
479 break;
480 }
481
482 block_counter += blocks;
483 }
484 }
485
smc_encode_init(AVCodecContext *avctx)486 static int smc_encode_init(AVCodecContext *avctx)
487 {
488 SMCContext *s = avctx->priv_data;
489
490 avctx->bits_per_coded_sample = 8;
491
492 s->prev_frame = av_frame_alloc();
493 if (!s->prev_frame)
494 return AVERROR(ENOMEM);
495
496 return 0;
497 }
498
smc_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet)499 static int smc_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
500 const AVFrame *frame, int *got_packet)
501 {
502 SMCContext *s = avctx->priv_data;
503 const AVFrame *pict = frame;
504 PutByteContext pb;
505 uint8_t *pal;
506 int ret;
507
508 ret = ff_alloc_packet(avctx, pkt, 8LL * avctx->height * avctx->width);
509 if (ret < 0)
510 return ret;
511
512 if (avctx->gop_size == 0 || !s->prev_frame->data[0] ||
513 (avctx->frame_number % avctx->gop_size) == 0) {
514 s->key_frame = 1;
515 } else {
516 s->key_frame = 0;
517 }
518
519 bytestream2_init_writer(&pb, pkt->data, pkt->size);
520
521 bytestream2_put_be32(&pb, 0x00);
522
523 pal = av_packet_new_side_data(pkt, AV_PKT_DATA_PALETTE, AVPALETTE_SIZE);
524 if (!pal)
525 return AVERROR(ENOMEM);
526 memcpy(pal, frame->data[1], AVPALETTE_SIZE);
527
528 smc_encode_stream(s, pict, &pb);
529
530 av_shrink_packet(pkt, bytestream2_tell_p(&pb));
531
532 pkt->data[0] = 0x0;
533
534 // write chunk length
535 AV_WB24(pkt->data + 1, pkt->size);
536
537 av_frame_unref(s->prev_frame);
538 ret = av_frame_ref(s->prev_frame, frame);
539 if (ret < 0) {
540 av_log(avctx, AV_LOG_ERROR, "cannot add reference\n");
541 return ret;
542 }
543
544 if (s->key_frame)
545 pkt->flags |= AV_PKT_FLAG_KEY;
546
547 *got_packet = 1;
548
549 return 0;
550 }
551
smc_encode_end(AVCodecContext *avctx)552 static int smc_encode_end(AVCodecContext *avctx)
553 {
554 SMCContext *s = (SMCContext *)avctx->priv_data;
555
556 av_frame_free(&s->prev_frame);
557
558 return 0;
559 }
560
561 const FFCodec ff_smc_encoder = {
562 .p.name = "smc",
563 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
564 .p.type = AVMEDIA_TYPE_VIDEO,
565 .p.id = AV_CODEC_ID_SMC,
566 .priv_data_size = sizeof(SMCContext),
567 .init = smc_encode_init,
568 FF_CODEC_ENCODE_CB(smc_encode_frame),
569 .close = smc_encode_end,
570 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE,
571 .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_PAL8,
572 AV_PIX_FMT_NONE},
573 };
574