1/* 2 * QuickTime RPZA Video Encoder 3 * 4 * This file is part of FFmpeg. 5 * 6 * FFmpeg is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * FFmpeg is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with FFmpeg; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21/** 22 * @file rpzaenc.c 23 * QT RPZA Video Encoder by Todd Kirby <doubleshot@pacbell.net> and David Adler 24 */ 25 26#include "libavutil/avassert.h" 27#include "libavutil/common.h" 28#include "libavutil/opt.h" 29 30#include "avcodec.h" 31#include "codec_internal.h" 32#include "encode.h" 33#include "put_bits.h" 34 35typedef struct RpzaContext { 36 AVClass *avclass; 37 38 int skip_frame_thresh; 39 int start_one_color_thresh; 40 int continue_one_color_thresh; 41 int sixteen_color_thresh; 42 43 AVFrame *prev_frame; // buffer for previous source frame 44 PutBitContext pb; // buffer for encoded frame data. 45 46 int frame_width; // width in pixels of source frame 47 int frame_height; // height in pixesl of source frame 48 49 int first_frame; // flag set to one when the first frame is being processed 50 // so that comparisons with previous frame data in not attempted 51} RpzaContext; 52 53typedef enum channel_offset { 54 RED = 2, 55 GREEN = 1, 56 BLUE = 0, 57} channel_offset; 58 59typedef struct rgb { 60 uint8_t r; 61 uint8_t g; 62 uint8_t b; 63} rgb; 64 65#define SQR(x) ((x) * (x)) 66 67/* 15 bit components */ 68#define GET_CHAN(color, chan) (((color) >> ((chan) * 5) & 0x1F) * 8) 69#define R(color) GET_CHAN(color, RED) 70#define G(color) GET_CHAN(color, GREEN) 71#define B(color) GET_CHAN(color, BLUE) 72 73typedef struct BlockInfo { 74 int row; 75 int col; 76 int block_width; 77 int block_height; 78 int image_width; 79 int image_height; 80 int block_index; 81 uint16_t start; 82 int rowstride; 83 int blocks_per_row; 84 int total_blocks; 85} BlockInfo; 86 87static void get_colors(uint8_t *min, uint8_t *max, uint8_t color4[4][3]) 88{ 89 uint8_t step; 90 91 color4[0][0] = min[0]; 92 color4[0][1] = min[1]; 93 color4[0][2] = min[2]; 94 95 color4[3][0] = max[0]; 96 color4[3][1] = max[1]; 97 color4[3][2] = max[2]; 98 99 // red components 100 step = (color4[3][0] - color4[0][0] + 1) / 3; 101 color4[1][0] = color4[0][0] + step; 102 color4[2][0] = color4[3][0] - step; 103 104 // green components 105 step = (color4[3][1] - color4[0][1] + 1) / 3; 106 color4[1][1] = color4[0][1] + step; 107 color4[2][1] = color4[3][1] - step; 108 109 // blue components 110 step = (color4[3][2] - color4[0][2] + 1) / 3; 111 color4[1][2] = color4[0][2] + step; 112 color4[2][2] = color4[3][2] - step; 113} 114 115/* Fill BlockInfo struct with information about a 4x4 block of the image */ 116static int get_block_info(BlockInfo *bi, int block) 117{ 118 bi->row = block / bi->blocks_per_row; 119 bi->col = block % bi->blocks_per_row; 120 121 // test for right edge block 122 if (bi->col == bi->blocks_per_row - 1 && (bi->image_width % 4) != 0) { 123 bi->block_width = bi->image_width % 4; 124 } else { 125 bi->block_width = 4; 126 } 127 128 // test for bottom edge block 129 if (bi->row == (bi->image_height / 4) && (bi->image_height % 4) != 0) { 130 bi->block_height = bi->image_height % 4; 131 } else { 132 bi->block_height = 4; 133 } 134 135 return block ? (bi->col * 4) + (bi->row * bi->rowstride * 4) : 0; 136} 137 138static uint16_t rgb24_to_rgb555(uint8_t *rgb24) 139{ 140 uint16_t rgb555 = 0; 141 uint32_t r, g, b; 142 143 r = rgb24[0] >> 3; 144 g = rgb24[1] >> 3; 145 b = rgb24[2] >> 3; 146 147 rgb555 |= (r << 10); 148 rgb555 |= (g << 5); 149 rgb555 |= (b << 0); 150 151 return rgb555; 152} 153 154/* 155 * Returns the total difference between two 24 bit color values 156 */ 157static int diff_colors(uint8_t *colorA, uint8_t *colorB) 158{ 159 int tot; 160 161 tot = SQR(colorA[0] - colorB[0]); 162 tot += SQR(colorA[1] - colorB[1]); 163 tot += SQR(colorA[2] - colorB[2]); 164 165 return tot; 166} 167 168/* 169 * Returns the maximum channel difference 170 */ 171static int max_component_diff(uint16_t *colorA, uint16_t *colorB) 172{ 173 int diff, max = 0; 174 175 diff = FFABS(R(colorA[0]) - R(colorB[0])); 176 if (diff > max) { 177 max = diff; 178 } 179 diff = FFABS(G(colorA[0]) - G(colorB[0])); 180 if (diff > max) { 181 max = diff; 182 } 183 diff = FFABS(B(colorA[0]) - B(colorB[0])); 184 if (diff > max) { 185 max = diff; 186 } 187 return max * 8; 188} 189 190/* 191 * Find the channel that has the largest difference between minimum and maximum 192 * color values. Put the minimum value in min, maximum in max and the channel 193 * in chan. 194 */ 195static void get_max_component_diff(BlockInfo *bi, uint16_t *block_ptr, 196 uint8_t *min, uint8_t *max, channel_offset *chan) 197{ 198 int x, y; 199 uint8_t min_r, max_r, min_g, max_g, min_b, max_b; 200 uint8_t r, g, b; 201 202 // fix warning about uninitialized vars 203 min_r = min_g = min_b = UINT8_MAX; 204 max_r = max_g = max_b = 0; 205 206 // loop thru and compare pixels 207 for (y = 0; y < bi->block_height; y++) { 208 for (x = 0; x < bi->block_width; x++) { 209 // TODO: optimize 210 min_r = FFMIN(R(block_ptr[x]), min_r); 211 min_g = FFMIN(G(block_ptr[x]), min_g); 212 min_b = FFMIN(B(block_ptr[x]), min_b); 213 214 max_r = FFMAX(R(block_ptr[x]), max_r); 215 max_g = FFMAX(G(block_ptr[x]), max_g); 216 max_b = FFMAX(B(block_ptr[x]), max_b); 217 } 218 block_ptr += bi->rowstride; 219 } 220 221 r = max_r - min_r; 222 g = max_g - min_g; 223 b = max_b - min_b; 224 225 if (r > g && r > b) { 226 *max = max_r; 227 *min = min_r; 228 *chan = RED; 229 } else if (g > b && g >= r) { 230 *max = max_g; 231 *min = min_g; 232 *chan = GREEN; 233 } else { 234 *max = max_b; 235 *min = min_b; 236 *chan = BLUE; 237 } 238} 239 240/* 241 * Compare two 4x4 blocks to determine if the total difference between the 242 * blocks is greater than the thresh parameter. Returns -1 if difference 243 * exceeds threshold or zero otherwise. 244 */ 245static int compare_blocks(uint16_t *block1, uint16_t *block2, BlockInfo *bi, int thresh) 246{ 247 int x, y, diff = 0; 248 for (y = 0; y < bi->block_height; y++) { 249 for (x = 0; x < bi->block_width; x++) { 250 diff = max_component_diff(&block1[x], &block2[x]); 251 if (diff >= thresh) { 252 return -1; 253 } 254 } 255 block1 += bi->rowstride; 256 block2 += bi->rowstride; 257 } 258 return 0; 259} 260 261/* 262 * Determine the fit of one channel to another within a 4x4 block. This 263 * is used to determine the best palette choices for 4-color encoding. 264 */ 265static int leastsquares(uint16_t *block_ptr, BlockInfo *bi, 266 channel_offset xchannel, channel_offset ychannel, 267 double *slope, double *y_intercept, double *correlation_coef) 268{ 269 double sumx = 0, sumy = 0, sumx2 = 0, sumy2 = 0, sumxy = 0, 270 sumx_sq = 0, sumy_sq = 0, tmp, tmp2; 271 int i, j, count; 272 uint8_t x, y; 273 274 count = bi->block_height * bi->block_width; 275 276 if (count < 2) 277 return -1; 278 279 for (i = 0; i < bi->block_height; i++) { 280 for (j = 0; j < bi->block_width; j++) { 281 x = GET_CHAN(block_ptr[j], xchannel); 282 y = GET_CHAN(block_ptr[j], ychannel); 283 sumx += x; 284 sumy += y; 285 sumx2 += x * x; 286 sumy2 += y * y; 287 sumxy += x * y; 288 } 289 block_ptr += bi->rowstride; 290 } 291 292 sumx_sq = sumx * sumx; 293 tmp = (count * sumx2 - sumx_sq); 294 295 // guard against div/0 296 if (tmp == 0) 297 return -2; 298 299 sumy_sq = sumy * sumy; 300 301 *slope = (sumx * sumy - sumxy) / tmp; 302 *y_intercept = (sumy - (*slope) * sumx) / count; 303 304 tmp2 = count * sumy2 - sumy_sq; 305 if (tmp2 == 0) { 306 *correlation_coef = 0.0; 307 } else { 308 *correlation_coef = (count * sumxy - sumx * sumy) / 309 sqrt(tmp * tmp2); 310 } 311 312 return 0; // success 313} 314 315/* 316 * Determine the amount of error in the leastsquares fit. 317 */ 318static int calc_lsq_max_fit_error(uint16_t *block_ptr, BlockInfo *bi, 319 int min, int max, int tmp_min, int tmp_max, 320 channel_offset xchannel, channel_offset ychannel) 321{ 322 int i, j, x, y; 323 int err; 324 int max_err = 0; 325 326 for (i = 0; i < bi->block_height; i++) { 327 for (j = 0; j < bi->block_width; j++) { 328 int x_inc, lin_y, lin_x; 329 x = GET_CHAN(block_ptr[j], xchannel); 330 y = GET_CHAN(block_ptr[j], ychannel); 331 332 /* calculate x_inc as the 4-color index (0..3) */ 333 x_inc = floor( (x - min) * 3.0 / (max - min) + 0.5); 334 x_inc = FFMAX(FFMIN(3, x_inc), 0); 335 336 /* calculate lin_y corresponding to x_inc */ 337 lin_y = (int)(tmp_min + (tmp_max - tmp_min) * x_inc / 3.0 + 0.5); 338 339 err = FFABS(lin_y - y); 340 if (err > max_err) 341 max_err = err; 342 343 /* calculate lin_x corresponding to x_inc */ 344 lin_x = (int)(min + (max - min) * x_inc / 3.0 + 0.5); 345 346 err = FFABS(lin_x - x); 347 if (err > max_err) 348 max_err += err; 349 } 350 block_ptr += bi->rowstride; 351 } 352 353 return max_err; 354} 355 356/* 357 * Find the closest match to a color within the 4-color palette 358 */ 359static int match_color(uint16_t *color, uint8_t colors[4][3]) 360{ 361 int ret = 0; 362 int smallest_variance = INT_MAX; 363 uint8_t dithered_color[3]; 364 365 for (int channel = 0; channel < 3; channel++) { 366 dithered_color[channel] = GET_CHAN(color[0], channel); 367 } 368 369 for (int palette_entry = 0; palette_entry < 4; palette_entry++) { 370 int variance = diff_colors(dithered_color, colors[palette_entry]); 371 372 if (variance < smallest_variance) { 373 smallest_variance = variance; 374 ret = palette_entry; 375 } 376 } 377 378 return ret; 379} 380 381/* 382 * Encode a block using the 4-color opcode and palette. return number of 383 * blocks encoded (until we implement multi-block 4 color runs this will 384 * always be 1) 385 */ 386static int encode_four_color_block(uint8_t *min_color, uint8_t *max_color, 387 PutBitContext *pb, uint16_t *block_ptr, BlockInfo *bi) 388{ 389 int x, y, idx; 390 uint8_t color4[4][3]; 391 uint16_t rounded_max, rounded_min; 392 393 // round min and max wider 394 rounded_min = rgb24_to_rgb555(min_color); 395 rounded_max = rgb24_to_rgb555(max_color); 396 397 // put a and b colors 398 // encode 4 colors = first 16 bit color with MSB zeroed and... 399 put_bits(pb, 16, rounded_max & ~0x8000); 400 // ...second 16 bit color with MSB on. 401 put_bits(pb, 16, rounded_min | 0x8000); 402 403 get_colors(min_color, max_color, color4); 404 405 for (y = 0; y < 4; y++) { 406 for (x = 0; x < 4; x++) { 407 idx = match_color(&block_ptr[x], color4); 408 put_bits(pb, 2, idx); 409 } 410 block_ptr += bi->rowstride; 411 } 412 return 1; // num blocks encoded 413} 414 415/* 416 * Copy a 4x4 block from the current frame buffer to the previous frame buffer. 417 */ 418static void update_block_in_prev_frame(const uint16_t *src_pixels, 419 uint16_t *dest_pixels, 420 const BlockInfo *bi, int block_counter) 421{ 422 const int y_size = FFMIN(4, bi->image_height - bi->row * 4); 423 424 for (int y = 0; y < y_size; y++) { 425 memcpy(dest_pixels, src_pixels, 8); 426 dest_pixels += bi->rowstride; 427 src_pixels += bi->rowstride; 428 } 429} 430 431/* 432 * update statistics for the specified block. If first_block, 433 * it initializes the statistics. Otherwise it updates the statistics IF THIS 434 * BLOCK IS SUITABLE TO CONTINUE A 1-COLOR RUN. That is, it checks whether 435 * the range of colors (since the routine was called first_block != 0) are 436 * all close enough intensities to be represented by a single color. 437 438 * The routine returns 0 if this block is too different to be part of 439 * the same run of 1-color blocks. The routine returns 1 if this 440 * block can be part of the same 1-color block run. 441 442 * If the routine returns 1, it also updates its arguments to include 443 * the statistics of this block. Otherwise, the stats are unchanged 444 * and don't include the current block. 445 */ 446static int update_block_stats(RpzaContext *s, BlockInfo *bi, uint16_t *block, 447 uint8_t min_color[3], uint8_t max_color[3], 448 int *total_rgb, int *total_pixels, 449 uint8_t avg_color[3], int first_block) 450{ 451 int x, y; 452 int is_in_range; 453 int total_pixels_blk; 454 int threshold; 455 456 uint8_t min_color_blk[3], max_color_blk[3]; 457 int total_rgb_blk[3]; 458 uint8_t avg_color_blk[3]; 459 460 if (first_block) { 461 min_color[0] = UINT8_MAX; 462 min_color[1] = UINT8_MAX; 463 min_color[2] = UINT8_MAX; 464 max_color[0] = 0; 465 max_color[1] = 0; 466 max_color[2] = 0; 467 total_rgb[0] = 0; 468 total_rgb[1] = 0; 469 total_rgb[2] = 0; 470 *total_pixels = 0; 471 threshold = s->start_one_color_thresh; 472 } else { 473 threshold = s->continue_one_color_thresh; 474 } 475 476 /* 477 The *_blk variables will include the current block. 478 Initialize them based on the blocks so far. 479 */ 480 min_color_blk[0] = min_color[0]; 481 min_color_blk[1] = min_color[1]; 482 min_color_blk[2] = min_color[2]; 483 max_color_blk[0] = max_color[0]; 484 max_color_blk[1] = max_color[1]; 485 max_color_blk[2] = max_color[2]; 486 total_rgb_blk[0] = total_rgb[0]; 487 total_rgb_blk[1] = total_rgb[1]; 488 total_rgb_blk[2] = total_rgb[2]; 489 total_pixels_blk = *total_pixels + bi->block_height * bi->block_width; 490 491 /* 492 Update stats for this block's pixels 493 */ 494 for (y = 0; y < bi->block_height; y++) { 495 for (x = 0; x < bi->block_width; x++) { 496 total_rgb_blk[0] += R(block[x]); 497 total_rgb_blk[1] += G(block[x]); 498 total_rgb_blk[2] += B(block[x]); 499 500 min_color_blk[0] = FFMIN(R(block[x]), min_color_blk[0]); 501 min_color_blk[1] = FFMIN(G(block[x]), min_color_blk[1]); 502 min_color_blk[2] = FFMIN(B(block[x]), min_color_blk[2]); 503 504 max_color_blk[0] = FFMAX(R(block[x]), max_color_blk[0]); 505 max_color_blk[1] = FFMAX(G(block[x]), max_color_blk[1]); 506 max_color_blk[2] = FFMAX(B(block[x]), max_color_blk[2]); 507 } 508 block += bi->rowstride; 509 } 510 511 /* 512 Calculate average color including current block. 513 */ 514 avg_color_blk[0] = total_rgb_blk[0] / total_pixels_blk; 515 avg_color_blk[1] = total_rgb_blk[1] / total_pixels_blk; 516 avg_color_blk[2] = total_rgb_blk[2] / total_pixels_blk; 517 518 /* 519 Are all the pixels within threshold of the average color? 520 */ 521 is_in_range = (max_color_blk[0] - avg_color_blk[0] <= threshold && 522 max_color_blk[1] - avg_color_blk[1] <= threshold && 523 max_color_blk[2] - avg_color_blk[2] <= threshold && 524 avg_color_blk[0] - min_color_blk[0] <= threshold && 525 avg_color_blk[1] - min_color_blk[1] <= threshold && 526 avg_color_blk[2] - min_color_blk[2] <= threshold); 527 528 if (is_in_range) { 529 /* 530 Set the output variables to include this block. 531 */ 532 min_color[0] = min_color_blk[0]; 533 min_color[1] = min_color_blk[1]; 534 min_color[2] = min_color_blk[2]; 535 max_color[0] = max_color_blk[0]; 536 max_color[1] = max_color_blk[1]; 537 max_color[2] = max_color_blk[2]; 538 total_rgb[0] = total_rgb_blk[0]; 539 total_rgb[1] = total_rgb_blk[1]; 540 total_rgb[2] = total_rgb_blk[2]; 541 *total_pixels = total_pixels_blk; 542 avg_color[0] = avg_color_blk[0]; 543 avg_color[1] = avg_color_blk[1]; 544 avg_color[2] = avg_color_blk[2]; 545 } 546 547 return is_in_range; 548} 549 550static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict) 551{ 552 BlockInfo bi; 553 int block_counter = 0; 554 int n_blocks; 555 int total_blocks; 556 int prev_block_offset; 557 int block_offset = 0; 558 uint8_t min = 0, max = 0; 559 channel_offset chan; 560 int i; 561 int tmp_min, tmp_max; 562 int total_rgb[3]; 563 uint8_t avg_color[3]; 564 int pixel_count; 565 uint8_t min_color[3], max_color[3]; 566 double slope, y_intercept, correlation_coef; 567 uint16_t *src_pixels = (uint16_t *)pict->data[0]; 568 uint16_t *prev_pixels = (uint16_t *)s->prev_frame->data[0]; 569 570 /* Number of 4x4 blocks in frame. */ 571 total_blocks = ((s->frame_width + 3) / 4) * ((s->frame_height + 3) / 4); 572 573 bi.image_width = s->frame_width; 574 bi.image_height = s->frame_height; 575 bi.rowstride = pict->linesize[0] / 2; 576 577 bi.blocks_per_row = (s->frame_width + 3) / 4; 578 579 while (block_counter < total_blocks) { 580 // SKIP CHECK 581 // make sure we have a valid previous frame and we're not writing 582 // a key frame 583 if (!s->first_frame) { 584 n_blocks = 0; 585 prev_block_offset = 0; 586 587 while (n_blocks < 32 && block_counter + n_blocks < total_blocks) { 588 589 block_offset = get_block_info(&bi, block_counter + n_blocks); 590 591 // multi-block opcodes cannot span multiple rows. 592 // If we're starting a new row, break out and write the opcode 593 /* TODO: Should eventually use bi.row here to determine when a 594 row break occurs, but that is currently breaking the 595 quicktime player. This is probably due to a bug in the 596 way I'm calculating the current row. 597 */ 598 if (prev_block_offset && block_offset - prev_block_offset > 12) { 599 break; 600 } 601 602 prev_block_offset = block_offset; 603 604 if (compare_blocks(&prev_pixels[block_offset], 605 &src_pixels[block_offset], &bi, s->skip_frame_thresh) != 0) { 606 // write out skipable blocks 607 if (n_blocks) { 608 609 // write skip opcode 610 put_bits(&s->pb, 8, 0x80 | (n_blocks - 1)); 611 block_counter += n_blocks; 612 613 goto post_skip; 614 } 615 break; 616 } 617 618 /* 619 * NOTE: we don't update skipped blocks in the previous frame buffer 620 * since skipped needs always to be compared against the first skipped 621 * block to avoid artifacts during gradual fade in/outs. 622 */ 623 624 // update_block_in_prev_frame(&src_pixels[block_offset], 625 // &prev_pixels[block_offset], &bi, block_counter + n_blocks); 626 627 n_blocks++; 628 } 629 630 // we're either at the end of the frame or we've reached the maximum 631 // of 32 blocks in a run. Write out the run. 632 if (n_blocks) { 633 // write skip opcode 634 put_bits(&s->pb, 8, 0x80 | (n_blocks - 1)); 635 block_counter += n_blocks; 636 637 continue; 638 } 639 640 } else { 641 block_offset = get_block_info(&bi, block_counter); 642 } 643post_skip : 644 645 // ONE COLOR CHECK 646 if (update_block_stats(s, &bi, &src_pixels[block_offset], 647 min_color, max_color, 648 total_rgb, &pixel_count, avg_color, 1)) { 649 prev_block_offset = block_offset; 650 651 n_blocks = 1; 652 653 /* update this block in the previous frame buffer */ 654 update_block_in_prev_frame(&src_pixels[block_offset], 655 &prev_pixels[block_offset], &bi, block_counter + n_blocks); 656 657 // check for subsequent blocks with the same color 658 while (n_blocks < 32 && block_counter + n_blocks < total_blocks) { 659 block_offset = get_block_info(&bi, block_counter + n_blocks); 660 661 // multi-block opcodes cannot span multiple rows. 662 // If we've hit end of a row, break out and write the opcode 663 if (block_offset - prev_block_offset > 12) { 664 break; 665 } 666 667 if (!update_block_stats(s, &bi, &src_pixels[block_offset], 668 min_color, max_color, 669 total_rgb, &pixel_count, avg_color, 0)) { 670 break; 671 } 672 673 prev_block_offset = block_offset; 674 675 /* update this block in the previous frame buffer */ 676 update_block_in_prev_frame(&src_pixels[block_offset], 677 &prev_pixels[block_offset], &bi, block_counter + n_blocks); 678 679 n_blocks++; 680 } 681 682 // write one color opcode. 683 put_bits(&s->pb, 8, 0xa0 | (n_blocks - 1)); 684 // write color to encode. 685 put_bits(&s->pb, 16, rgb24_to_rgb555(avg_color)); 686 // skip past the blocks we've just encoded. 687 block_counter += n_blocks; 688 } else { // FOUR COLOR CHECK 689 int err = 0; 690 691 // get max component diff for block 692 get_max_component_diff(&bi, &src_pixels[block_offset], &min, &max, &chan); 693 694 min_color[0] = 0; 695 max_color[0] = 0; 696 min_color[1] = 0; 697 max_color[1] = 0; 698 min_color[2] = 0; 699 max_color[2] = 0; 700 701 // run least squares against other two components 702 for (i = 0; i < 3; i++) { 703 if (i == chan) { 704 min_color[i] = min; 705 max_color[i] = max; 706 continue; 707 } 708 709 slope = y_intercept = correlation_coef = 0; 710 711 if (leastsquares(&src_pixels[block_offset], &bi, chan, i, 712 &slope, &y_intercept, &correlation_coef)) { 713 min_color[i] = GET_CHAN(src_pixels[block_offset], i); 714 max_color[i] = GET_CHAN(src_pixels[block_offset], i); 715 } else { 716 tmp_min = (int)(0.5 + min * slope + y_intercept); 717 tmp_max = (int)(0.5 + max * slope + y_intercept); 718 719 av_assert0(tmp_min <= tmp_max); 720 // clamp min and max color values 721 tmp_min = av_clip_uint8(tmp_min); 722 tmp_max = av_clip_uint8(tmp_max); 723 724 err = FFMAX(calc_lsq_max_fit_error(&src_pixels[block_offset], &bi, 725 min, max, tmp_min, tmp_max, chan, i), err); 726 727 min_color[i] = tmp_min; 728 max_color[i] = tmp_max; 729 } 730 } 731 732 if (err > s->sixteen_color_thresh) { // DO SIXTEEN COLOR BLOCK 733 uint16_t *row_ptr; 734 int y_size, x_size, rgb555; 735 736 block_offset = get_block_info(&bi, block_counter); 737 738 row_ptr = &src_pixels[block_offset]; 739 y_size = FFMIN(4, bi.image_height - bi.row * 4); 740 x_size = FFMIN(4, bi.image_width - bi.col * 4); 741 742 for (int y = 0; y < y_size; y++) { 743 for (int x = 0; x < x_size; x++) { 744 rgb555 = row_ptr[x] & ~0x8000; 745 746 put_bits(&s->pb, 16, rgb555); 747 } 748 for (int x = x_size; x < 4; x++) 749 put_bits(&s->pb, 16, 0); 750 row_ptr += bi.rowstride; 751 } 752 753 for (int y = y_size; y < 4; y++) { 754 for (int x = 0; x < 4; x++) 755 put_bits(&s->pb, 16, 0); 756 } 757 758 block_counter++; 759 } else { // FOUR COLOR BLOCK 760 block_counter += encode_four_color_block(min_color, max_color, 761 &s->pb, &src_pixels[block_offset], &bi); 762 } 763 764 /* update this block in the previous frame buffer */ 765 update_block_in_prev_frame(&src_pixels[block_offset], 766 &prev_pixels[block_offset], &bi, block_counter); 767 } 768 } 769} 770 771static int rpza_encode_init(AVCodecContext *avctx) 772{ 773 RpzaContext *s = avctx->priv_data; 774 775 s->frame_width = avctx->width; 776 s->frame_height = avctx->height; 777 778 s->prev_frame = av_frame_alloc(); 779 if (!s->prev_frame) 780 return AVERROR(ENOMEM); 781 782 return 0; 783} 784 785static int rpza_encode_frame(AVCodecContext *avctx, AVPacket *pkt, 786 const AVFrame *frame, int *got_packet) 787{ 788 RpzaContext *s = avctx->priv_data; 789 const AVFrame *pict = frame; 790 uint8_t *buf; 791 int ret = ff_alloc_packet(avctx, pkt, 6LL * avctx->height * avctx->width); 792 793 if (ret < 0) 794 return ret; 795 796 init_put_bits(&s->pb, pkt->data, pkt->size); 797 798 // skip 4 byte header, write it later once the size of the chunk is known 799 put_bits32(&s->pb, 0x00); 800 801 if (!s->prev_frame->data[0]) { 802 s->first_frame = 1; 803 s->prev_frame->format = pict->format; 804 s->prev_frame->width = pict->width; 805 s->prev_frame->height = pict->height; 806 ret = av_frame_get_buffer(s->prev_frame, 0); 807 if (ret < 0) 808 return ret; 809 } else { 810 s->first_frame = 0; 811 } 812 813 rpza_encode_stream(s, pict); 814 815 flush_put_bits(&s->pb); 816 817 av_shrink_packet(pkt, put_bytes_output(&s->pb)); 818 buf = pkt->data; 819 820 // write header opcode 821 buf[0] = 0xe1; // chunk opcode 822 823 // write chunk length 824 AV_WB24(buf + 1, pkt->size); 825 826 *got_packet = 1; 827 828 return 0; 829} 830 831static int rpza_encode_end(AVCodecContext *avctx) 832{ 833 RpzaContext *s = (RpzaContext *)avctx->priv_data; 834 835 av_frame_free(&s->prev_frame); 836 837 return 0; 838} 839 840#define OFFSET(x) offsetof(RpzaContext, x) 841#define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM 842static const AVOption options[] = { 843 { "skip_frame_thresh", NULL, OFFSET(skip_frame_thresh), AV_OPT_TYPE_INT, {.i64=1}, 0, 24, VE}, 844 { "start_one_color_thresh", NULL, OFFSET(start_one_color_thresh), AV_OPT_TYPE_INT, {.i64=1}, 0, 24, VE}, 845 { "continue_one_color_thresh", NULL, OFFSET(continue_one_color_thresh), AV_OPT_TYPE_INT, {.i64=0}, 0, 24, VE}, 846 { "sixteen_color_thresh", NULL, OFFSET(sixteen_color_thresh), AV_OPT_TYPE_INT, {.i64=1}, 0, 24, VE}, 847 { NULL }, 848}; 849 850static const AVClass rpza_class = { 851 .class_name = "rpza", 852 .item_name = av_default_item_name, 853 .option = options, 854 .version = LIBAVUTIL_VERSION_INT, 855}; 856 857const FFCodec ff_rpza_encoder = { 858 .p.name = "rpza", 859 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime video (RPZA)"), 860 .p.type = AVMEDIA_TYPE_VIDEO, 861 .p.id = AV_CODEC_ID_RPZA, 862 .priv_data_size = sizeof(RpzaContext), 863 .p.priv_class = &rpza_class, 864 .init = rpza_encode_init, 865 FF_CODEC_ENCODE_CB(rpza_encode_frame), 866 .close = rpza_encode_end, 867 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 868 .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB555, 869 AV_PIX_FMT_NONE}, 870}; 871