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