2 * QuickTime Graphics (SMC) Video Encoder
3 * Copyright (c) 2021 The FFmpeg project
5 * This file is part of FFmpeg.
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.
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.
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
24 * QT SMC Video Encoder by Paul B. Mahol
27 #include "libavutil/common.h"
30 #include "codec_internal.h"
32 #include "bytestream.h"
38 #define COLORS_PER_TABLE 256
40 typedef struct SMCContext
{
41 AVFrame
*prev_frame
; // buffer for previous source frame
46 uint8_t distinct_values
[16];
47 uint8_t next_distinct_values
[16];
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
];
56 #define ADVANCE_BLOCK(pixel_ptr, row_ptr, nb_blocks) \
58 for (int block = 0; block < nb_blocks && pixel_ptr && row_ptr; block++) { \
61 if (pixel_ptr - row_ptr >= width) \
63 row_ptr += stride * 4; \
64 pixel_ptr = row_ptr; \
71 static int smc_cmp_values(const void *a
, const void *b
)
73 const uint8_t *aa
= a
, *bb
= b
;
75 return FFDIFFSIGN(aa
[0], bb
[0]);
78 static int count_distinct_items(const uint8_t *block_values
,
79 uint8_t *distinct_values
,
84 distinct_values
[0] = block_values
[0];
85 for (int i
= 1; i
< size
; i
++) {
86 if (block_values
[i
] != block_values
[i
-1]) {
87 distinct_values
[n
] = block_values
[i
];
95 #define CACHE_PAIR(x) \
96 (s->color_pairs[i][0] == distinct_values[x] || \
97 s->color_pairs[i][1] == distinct_values[x])
99 #define CACHE_QUAD(x) \
100 (s->color_quads[i][0] == distinct_values[x] || \
101 s->color_quads[i][1] == distinct_values[x] || \
102 s->color_quads[i][2] == distinct_values[x] || \
103 s->color_quads[i][3] == distinct_values[x])
105 #define CACHE_OCTET(x) \
106 (s->color_octets[i][0] == distinct_values[x] || \
107 s->color_octets[i][1] == distinct_values[x] || \
108 s->color_octets[i][2] == distinct_values[x] || \
109 s->color_octets[i][3] == distinct_values[x] || \
110 s->color_octets[i][4] == distinct_values[x] || \
111 s->color_octets[i][5] == distinct_values[x] || \
112 s->color_octets[i][6] == distinct_values[x] || \
113 s->color_octets[i][7] == distinct_values[x])
115 static void smc_encode_stream(SMCContext
*s
, const AVFrame
*frame
,
118 const uint8_t *src_pixels
= (const uint8_t *)frame
->data
[0];
119 const ptrdiff_t stride
= frame
->linesize
[0];
120 const uint8_t *prev_pixels
= (const uint8_t *)s
->prev_frame
->data
[0];
121 const ptrdiff_t prev_stride
= s
->prev_frame
->linesize
[0];
122 uint8_t *distinct_values
= s
->distinct_values
;
123 const uint8_t *pixel_ptr
, *row_ptr
;
124 const int height
= frame
->height
;
125 const int width
= frame
->width
;
126 int block_counter
= 0;
127 int color_pair_index
= 0;
128 int color_quad_index
= 0;
129 int color_octet_index
= 0;
130 int color_table_index
; /* indexes to color pair, quad, or octet tables */
135 /* Number of 4x4 blocks in frame. */
136 total_blocks
= ((width
+ 3) / 4) * ((height
+ 3) / 4);
138 pixel_ptr
= row_ptr
= src_pixels
;
140 while (block_counter
< total_blocks
) {
141 const uint8_t *xpixel_ptr
= pixel_ptr
;
142 const uint8_t *xrow_ptr
= row_ptr
;
143 int intra_skip_blocks
= 0;
144 int inter_skip_blocks
= 0;
145 int coded_distinct
= 0;
146 int coded_blocks
= 0;
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 const int x_size
= FFMIN(4, width
- cur_x
);
158 for (int y
= 0; y
< y_size
; y
++) {
159 const uint8_t *prev_pixel_ptr
= prev_pixels
+ (y
+ cur_y
) * prev_stride
+ cur_x
;
161 compare
|= !!memcmp(prev_pixel_ptr
, pixel_ptr
+ y
* stride
, x_size
);
170 if (inter_skip_blocks
>= 256)
173 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, 1)
176 pixel_ptr
= xpixel_ptr
;
181 while (block_counter
> 0 && block_counter
+ intra_skip_blocks
< total_blocks
) {
182 const int y_size
= FFMIN(4, height
- cur_y
);
183 const int x_size
= FFMIN(4, width
- cur_x
);
184 const ptrdiff_t offset
= xpixel_ptr
- src_pixels
;
185 const int sy
= offset
/ stride
;
186 const int sx
= offset
% stride
;
187 const int ny
= sx
< 4 ? FFMAX(sy
- 4, 0) : sy
;
188 const int nx
= sx
< 4 ? FFMAX(width
- 4 + (width
& 3), 0) : sx
- 4;
189 const uint8_t *old_pixel_ptr
= src_pixels
+ nx
+ ny
* stride
;
192 for (int y
= 0; y
< y_size
; y
++) {
193 compare
|= !!memcmp(old_pixel_ptr
+ y
* stride
, pixel_ptr
+ y
* stride
, x_size
);
202 if (intra_skip_blocks
>= 256)
205 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, 1)
208 pixel_ptr
= xpixel_ptr
;
213 while (block_counter
+ coded_blocks
< total_blocks
&& coded_blocks
< 256) {
214 const int y_size
= FFMIN(4, height
- cur_y
);
215 const int x_size
= FFMIN(4, width
- cur_x
);
216 const int nb_elements
= x_size
* y_size
;
217 uint8_t block_values
[16] = { 0 };
218 for (int y
= 0; y
< y_size
; y
++)
219 memcpy(block_values
+ y
* x_size
, pixel_ptr
+ y
* stride
, x_size
);
221 qsort(block_values
, nb_elements
, sizeof(block_values
[0]), smc_cmp_values
);
222 s
->next_nb_distinct
= count_distinct_items(block_values
, s
->next_distinct_values
, nb_elements
);
223 if (coded_blocks
== 0) {
224 memcpy(distinct_values
, s
->next_distinct_values
, sizeof(s
->distinct_values
));
225 s
->nb_distinct
= s
->next_nb_distinct
;
227 if (s
->next_nb_distinct
!= s
->nb_distinct
||
228 memcmp(distinct_values
, s
->next_distinct_values
, s
->nb_distinct
)) {
232 s
->mono_value
= block_values
[0];
234 coded_distinct
= s
->nb_distinct
;
236 if (coded_distinct
> 1 && coded_blocks
>= 16)
239 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, 1)
242 pixel_ptr
= xpixel_ptr
;
247 blocks
= coded_distinct
<= 8 ? coded_blocks
: 0;
248 distinct
= coded_distinct
;
250 if (intra_skip_blocks
>= blocks
&& intra_skip_blocks
>= inter_skip_blocks
) {
252 blocks
= intra_skip_blocks
;
255 if (intra_skip_blocks
> 16 && intra_skip_blocks
>= inter_skip_blocks
&&
256 intra_skip_blocks
>= blocks
) {
258 blocks
= intra_skip_blocks
;
261 if (inter_skip_blocks
>= blocks
&& inter_skip_blocks
> intra_skip_blocks
) {
263 blocks
= inter_skip_blocks
;
266 if (inter_skip_blocks
> 16 && inter_skip_blocks
> intra_skip_blocks
&&
267 inter_skip_blocks
>= blocks
) {
269 blocks
= inter_skip_blocks
;
273 blocks
= coded_blocks
;
274 distinct
= coded_distinct
;
280 bytestream2_put_byte(pb
, 0x60 | (blocks
- 1));
282 bytestream2_put_byte(pb
, 0x70);
283 bytestream2_put_byte(pb
, blocks
- 1);
285 bytestream2_put_byte(pb
, s
->mono_value
);
286 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, blocks
)
290 for (int i
= 0; i
< COLORS_PER_TABLE
; i
++) {
298 if (cache_index
>= 0) {
299 bytestream2_put_byte(pb
, 0x90 | (blocks
- 1));
300 bytestream2_put_byte(pb
, cache_index
);
301 color_table_index
= cache_index
;
303 bytestream2_put_byte(pb
, 0x80 | (blocks
- 1));
305 color_table_index
= color_pair_index
;
306 for (int i
= 0; i
< CPAIR
; i
++) {
307 s
->color_pairs
[color_table_index
][i
] = distinct_values
[i
];
308 bytestream2_put_byte(pb
, distinct_values
[i
]);
312 if (color_pair_index
== COLORS_PER_TABLE
)
313 color_pair_index
= 0;
316 for (int i
= 0; i
< blocks
; i
++) {
317 const int y_size
= FFMIN(4, height
- cur_y
);
318 const int x_size
= FFMIN(4, width
- cur_x
);
319 uint8_t value
= s
->color_pairs
[color_table_index
][1];
323 for (int y
= 0; y
< y_size
; y
++) {
324 for (int x
= 0; x
< x_size
; x
++) {
325 flags
|= (value
== pixel_ptr
[x
+ y
* stride
]) << shift
;
331 bytestream2_put_be16(pb
, flags
);
333 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, 1)
339 for (int i
= 0; i
< COLORS_PER_TABLE
; i
++) {
349 if (cache_index
>= 0) {
350 bytestream2_put_byte(pb
, 0xB0 | (blocks
- 1));
351 bytestream2_put_byte(pb
, cache_index
);
352 color_table_index
= cache_index
;
354 bytestream2_put_byte(pb
, 0xA0 | (blocks
- 1));
356 color_table_index
= color_quad_index
;
357 for (int i
= 0; i
< CQUAD
; i
++) {
358 s
->color_quads
[color_table_index
][i
] = distinct_values
[i
];
359 bytestream2_put_byte(pb
, distinct_values
[i
]);
363 if (color_quad_index
== COLORS_PER_TABLE
)
364 color_quad_index
= 0;
367 for (int i
= 0; i
< blocks
; i
++) {
368 const int y_size
= FFMIN(4, height
- cur_y
);
369 const int x_size
= FFMIN(4, width
- cur_x
);
374 for (int k
= 0; k
< 4; k
++)
375 quad
[k
] = s
->color_quads
[color_table_index
][k
];
377 for (int y
= 0; y
< y_size
; y
++) {
378 for (int x
= 0; x
< x_size
; x
++) {
379 int pixel
= pixel_ptr
[x
+ y
* stride
];
382 for (int w
= 0; w
< CQUAD
; w
++) {
383 if (quad
[w
] == pixel
) {
389 flags
|= idx
<< shift
;
393 shift
-= 2 * (4 - x_size
);
396 bytestream2_put_be32(pb
, flags
);
398 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, 1)
406 for (int i
= 0; i
< COLORS_PER_TABLE
; i
++) {
407 if (CACHE_OCTET(0) &&
420 if (cache_index
>= 0) {
421 bytestream2_put_byte(pb
, 0xD0 | (blocks
- 1));
422 bytestream2_put_byte(pb
, cache_index
);
423 color_table_index
= cache_index
;
425 bytestream2_put_byte(pb
, 0xC0 | (blocks
- 1));
427 color_table_index
= color_octet_index
;
428 for (int i
= 0; i
< COCTET
; i
++) {
429 s
->color_octets
[color_table_index
][i
] = distinct_values
[i
];
430 bytestream2_put_byte(pb
, distinct_values
[i
]);
434 if (color_octet_index
== COLORS_PER_TABLE
)
435 color_octet_index
= 0;
438 for (int i
= 0; i
< blocks
; i
++) {
439 const int y_size
= FFMIN(4, height
- cur_y
);
440 const int x_size
= FFMIN(4, width
- cur_x
);
445 for (int k
= 0; k
< 8; k
++)
446 octet
[k
] = s
->color_octets
[color_table_index
][k
];
448 for (int y
= 0; y
< y_size
; y
++) {
449 for (int x
= 0; x
< x_size
; x
++) {
450 int pixel
= pixel_ptr
[x
+ y
* stride
];
453 for (int w
= 0; w
< COCTET
; w
++) {
454 if (octet
[w
] == pixel
) {
460 flags
|= idx
<< shift
;
464 shift
-= 3 * (4 - x_size
);
467 bytestream2_put_be16(pb
, ((flags
>> 32) & 0xFFF0) | ((flags
>> 8) & 0xF));
468 bytestream2_put_be16(pb
, ((flags
>> 20) & 0xFFF0) | ((flags
>> 4) & 0xF));
469 bytestream2_put_be16(pb
, ((flags
>> 8) & 0xFFF0) | ((flags
>> 0) & 0xF));
471 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, 1)
475 bytestream2_put_byte(pb
, 0xE0 | (blocks
- 1));
476 for (int i
= 0; i
< blocks
; i
++) {
477 const int y_size
= FFMIN(4, height
- cur_y
);
478 const int x_size
= FFMIN(4, width
- cur_x
);
479 for (int y
= 0; y
< y_size
; y
++) {
480 for (int x
= 0; x
< x_size
; x
++)
481 bytestream2_put_byte(pb
, pixel_ptr
[x
+ y
* stride
]);
482 for (int x
= x_size
; x
< 4; x
++)
483 bytestream2_put_byte(pb
, 0);
486 for (int y
= y_size
; y
< 4; y
++) {
487 for (int x
= 0; x
< 4; x
++)
488 bytestream2_put_byte(pb
, 0);
491 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, 1)
495 bytestream2_put_byte(pb
, 0x20 | (blocks
- 1));
496 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, blocks
)
499 bytestream2_put_byte(pb
, 0x30);
500 bytestream2_put_byte(pb
, blocks
- 1);
501 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, blocks
)
504 bytestream2_put_byte(pb
, 0x00 | (blocks
- 1));
505 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, blocks
)
508 bytestream2_put_byte(pb
, 0x10);
509 bytestream2_put_byte(pb
, blocks
- 1);
510 ADVANCE_BLOCK(pixel_ptr
, row_ptr
, blocks
)
514 block_counter
+= blocks
;
518 static int smc_encode_init(AVCodecContext
*avctx
)
520 SMCContext
*s
= avctx
->priv_data
;
522 avctx
->bits_per_coded_sample
= 8;
524 s
->prev_frame
= av_frame_alloc();
526 return AVERROR(ENOMEM
);
531 static int smc_encode_frame(AVCodecContext
*avctx
, AVPacket
*pkt
,
532 const AVFrame
*frame
, int *got_packet
)
534 SMCContext
*s
= avctx
->priv_data
;
535 const AVFrame
*pict
= frame
;
540 ret
= ff_alloc_packet(avctx
, pkt
, 8LL * avctx
->height
* avctx
->width
);
544 if (avctx
->gop_size
== 0 || !s
->prev_frame
->data
[0] ||
545 (avctx
->frame_num
% avctx
->gop_size
) == 0) {
551 bytestream2_init_writer(&pb
, pkt
->data
, pkt
->size
);
553 bytestream2_put_be32(&pb
, 0x00);
555 pal
= av_packet_new_side_data(pkt
, AV_PKT_DATA_PALETTE
, AVPALETTE_SIZE
);
557 return AVERROR(ENOMEM
);
558 memcpy(pal
, frame
->data
[1], AVPALETTE_SIZE
);
560 smc_encode_stream(s
, pict
, &pb
);
562 av_shrink_packet(pkt
, bytestream2_tell_p(&pb
));
566 // write chunk length
567 AV_WB24(pkt
->data
+ 1, pkt
->size
);
569 ret
= av_frame_replace(s
->prev_frame
, frame
);
571 av_log(avctx
, AV_LOG_ERROR
, "cannot add reference\n");
576 pkt
->flags
|= AV_PKT_FLAG_KEY
;
583 static int smc_encode_end(AVCodecContext
*avctx
)
585 SMCContext
*s
= avctx
->priv_data
;
587 av_frame_free(&s
->prev_frame
);
592 const FFCodec ff_smc_encoder
= {
594 CODEC_LONG_NAME("QuickTime Graphics (SMC)"),
595 .p
.type
= AVMEDIA_TYPE_VIDEO
,
596 .p
.id
= AV_CODEC_ID_SMC
,
597 .p
.capabilities
= AV_CODEC_CAP_DR1
| AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE
,
598 .priv_data_size
= sizeof(SMCContext
),
599 .init
= smc_encode_init
,
600 FF_CODEC_ENCODE_CB(smc_encode_frame
),
601 .close
= smc_encode_end
,
602 .p
.pix_fmts
= (const enum AVPixelFormat
[]) { AV_PIX_FMT_PAL8
,