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 40typedef 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 69static 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 76static 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 113static 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 486static 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 499static 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 552static 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 561const 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