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