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