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;
85 } BlockInfo;
86 
87 static void get_colors(const uint8_t *min, const 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 */
116 static 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 
138 static uint16_t rgb24_to_rgb555(const 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  */
157 static int diff_colors(const uint8_t *colorA, const 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  */
171 static int max_component_diff(const uint16_t *colorA, const 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  */
195 static void get_max_component_diff(const BlockInfo *bi, const 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  */
245 static int compare_blocks(const uint16_t *block1, const uint16_t *block2,
246  const BlockInfo *bi, int thresh)
247 {
248  int x, y, diff = 0;
249  for (y = 0; y < bi->block_height; y++) {
250  for (x = 0; x < bi->block_width; x++) {
251  diff = max_component_diff(&block1[x], &block2[x]);
252  if (diff >= thresh) {
253  return -1;
254  }
255  }
256  block1 += bi->rowstride;
257  block2 += bi->rowstride;
258  }
259  return 0;
260 }
261 
262 /*
263  * Determine the fit of one channel to another within a 4x4 block. This
264  * is used to determine the best palette choices for 4-color encoding.
265  */
266 static int leastsquares(const uint16_t *block_ptr, const BlockInfo *bi,
267  channel_offset xchannel, channel_offset ychannel,
268  double *slope, double *y_intercept, double *correlation_coef)
269 {
270  double sumx = 0, sumy = 0, sumx2 = 0, sumy2 = 0, sumxy = 0,
271  sumx_sq = 0, sumy_sq = 0, tmp, tmp2;
272  int i, j, count;
273  uint8_t x, y;
274 
275  count = bi->block_height * bi->block_width;
276 
277  if (count < 2)
278  return -1;
279 
280  for (i = 0; i < bi->block_height; i++) {
281  for (j = 0; j < bi->block_width; j++){
282  x = GET_CHAN(block_ptr[j], xchannel);
283  y = GET_CHAN(block_ptr[j], ychannel);
284  sumx += x;
285  sumy += y;
286  sumx2 += x * x;
287  sumy2 += y * y;
288  sumxy += x * y;
289  }
290  block_ptr += bi->rowstride;
291  }
292 
293  sumx_sq = sumx * sumx;
294  tmp = (count * sumx2 - sumx_sq);
295 
296  // guard against div/0
297  if (tmp == 0)
298  return -2;
299 
300  sumy_sq = sumy * sumy;
301 
302  *slope = (sumx * sumy - sumxy) / tmp;
303  *y_intercept = (sumy - (*slope) * sumx) / count;
304 
305  tmp2 = count * sumy2 - sumy_sq;
306  if (tmp2 == 0) {
307  *correlation_coef = 0.0;
308  } else {
309  *correlation_coef = (count * sumxy - sumx * sumy) /
310  sqrt(tmp * tmp2);
311  }
312 
313  return 0; // success
314 }
315 
316 /*
317  * Determine the amount of error in the leastsquares fit.
318  */
319 static int calc_lsq_max_fit_error(const uint16_t *block_ptr, const BlockInfo *bi,
320  int min, int max, int tmp_min, int tmp_max,
321  channel_offset xchannel, channel_offset ychannel)
322 {
323  int i, j, x, y;
324  int err;
325  int max_err = 0;
326 
327  for (i = 0; i < bi->block_height; i++) {
328  for (j = 0; j < bi->block_width; j++){
329  int x_inc, lin_y, lin_x;
330  x = GET_CHAN(block_ptr[j], xchannel);
331  y = GET_CHAN(block_ptr[j], ychannel);
332 
333  /* calculate x_inc as the 4-color index (0..3) */
334  x_inc = floor( (x - min) * 3.0 / (max - min) + 0.5);
335  x_inc = FFMAX(FFMIN(3, x_inc), 0);
336 
337  /* calculate lin_y corresponding to x_inc */
338  lin_y = (int)(tmp_min + (tmp_max - tmp_min) * x_inc / 3.0 + 0.5);
339 
340  err = FFABS(lin_y - y);
341  if (err > max_err)
342  max_err = err;
343 
344  /* calculate lin_x corresponding to x_inc */
345  lin_x = (int)(min + (max - min) * x_inc / 3.0 + 0.5);
346 
347  err = FFABS(lin_x - x);
348  if (err > max_err)
349  max_err += err;
350  }
351  block_ptr += bi->rowstride;
352  }
353 
354  return max_err;
355 }
356 
357 /*
358  * Find the closest match to a color within the 4-color palette
359  */
360 static int match_color(const uint16_t *color, uint8_t colors[4][3])
361 {
362  int ret = 0;
363  int smallest_variance = INT_MAX;
364  uint8_t dithered_color[3];
365 
366  for (int channel = 0; channel < 3; channel++) {
367  dithered_color[channel] = GET_CHAN(color[0], channel);
368  }
369 
370  for (int palette_entry = 0; palette_entry < 4; palette_entry++) {
371  int variance = diff_colors(dithered_color, colors[palette_entry]);
372 
373  if (variance < smallest_variance) {
374  smallest_variance = variance;
375  ret = palette_entry;
376  }
377  }
378 
379  return ret;
380 }
381 
382 /*
383  * Encode a block using the 4-color opcode and palette. return number of
384  * blocks encoded (until we implement multi-block 4 color runs this will
385  * always be 1)
386  */
387 static int encode_four_color_block(const uint8_t *min_color, const uint8_t *max_color,
388  PutBitContext *pb, const uint16_t *block_ptr, const BlockInfo *bi)
389 {
390  int x, y, idx;
391  uint8_t color4[4][3];
392  uint16_t rounded_max, rounded_min;
393 
394  // round min and max wider
395  rounded_min = rgb24_to_rgb555(min_color);
396  rounded_max = rgb24_to_rgb555(max_color);
397 
398  // put a and b colors
399  // encode 4 colors = first 16 bit color with MSB zeroed and...
400  put_bits(pb, 16, rounded_max & ~0x8000);
401  // ...second 16 bit color with MSB on.
402  put_bits(pb, 16, rounded_min | 0x8000);
403 
404  get_colors(min_color, max_color, color4);
405 
406  for (y = 0; y < 4; y++) {
407  for (x = 0; x < 4; x++) {
408  idx = match_color(&block_ptr[x], color4);
409  put_bits(pb, 2, idx);
410  }
411  block_ptr += bi->rowstride;
412  }
413  return 1; // num blocks encoded
414 }
415 
416 /*
417  * Copy a 4x4 block from the current frame buffer to the previous frame buffer.
418  */
419 static void update_block_in_prev_frame(const uint16_t *src_pixels,
420  uint16_t *dest_pixels,
421  const BlockInfo *bi, int block_counter)
422 {
423  for (int y = 0; y < 4; y++) {
424  memcpy(dest_pixels, src_pixels, 8);
425  dest_pixels += bi->rowstride;
426  src_pixels += bi->rowstride;
427  }
428 }
429 
430 /*
431  * update statistics for the specified block. If first_block,
432  * it initializes the statistics. Otherwise it updates the statistics IF THIS
433  * BLOCK IS SUITABLE TO CONTINUE A 1-COLOR RUN. That is, it checks whether
434  * the range of colors (since the routine was called first_block != 0) are
435  * all close enough intensities to be represented by a single color.
436 
437  * The routine returns 0 if this block is too different to be part of
438  * the same run of 1-color blocks. The routine returns 1 if this
439  * block can be part of the same 1-color block run.
440 
441  * If the routine returns 1, it also updates its arguments to include
442  * the statistics of this block. Otherwise, the stats are unchanged
443  * and don't include the current block.
444  */
445 static int update_block_stats(RpzaContext *s, const BlockInfo *bi, const uint16_t *block,
446  uint8_t min_color[3], uint8_t max_color[3],
447  int *total_rgb, int *total_pixels,
448  uint8_t avg_color[3], int first_block)
449 {
450  int x, y;
451  int is_in_range;
452  int total_pixels_blk;
453  int threshold;
454 
455  uint8_t min_color_blk[3], max_color_blk[3];
456  int total_rgb_blk[3];
457  uint8_t avg_color_blk[3];
458 
459  if (first_block) {
460  min_color[0] = UINT8_MAX;
461  min_color[1] = UINT8_MAX;
462  min_color[2] = UINT8_MAX;
463  max_color[0] = 0;
464  max_color[1] = 0;
465  max_color[2] = 0;
466  total_rgb[0] = 0;
467  total_rgb[1] = 0;
468  total_rgb[2] = 0;
469  *total_pixels = 0;
470  threshold = s->start_one_color_thresh;
471  } else {
472  threshold = s->continue_one_color_thresh;
473  }
474 
475  /*
476  The *_blk variables will include the current block.
477  Initialize them based on the blocks so far.
478  */
479  min_color_blk[0] = min_color[0];
480  min_color_blk[1] = min_color[1];
481  min_color_blk[2] = min_color[2];
482  max_color_blk[0] = max_color[0];
483  max_color_blk[1] = max_color[1];
484  max_color_blk[2] = max_color[2];
485  total_rgb_blk[0] = total_rgb[0];
486  total_rgb_blk[1] = total_rgb[1];
487  total_rgb_blk[2] = total_rgb[2];
488  total_pixels_blk = *total_pixels + bi->block_height * bi->block_width;
489 
490  /*
491  Update stats for this block's pixels
492  */
493  for (y = 0; y < bi->block_height; y++) {
494  for (x = 0; x < bi->block_width; x++) {
495  total_rgb_blk[0] += R(block[x]);
496  total_rgb_blk[1] += G(block[x]);
497  total_rgb_blk[2] += B(block[x]);
498 
499  min_color_blk[0] = FFMIN(R(block[x]), min_color_blk[0]);
500  min_color_blk[1] = FFMIN(G(block[x]), min_color_blk[1]);
501  min_color_blk[2] = FFMIN(B(block[x]), min_color_blk[2]);
502 
503  max_color_blk[0] = FFMAX(R(block[x]), max_color_blk[0]);
504  max_color_blk[1] = FFMAX(G(block[x]), max_color_blk[1]);
505  max_color_blk[2] = FFMAX(B(block[x]), max_color_blk[2]);
506  }
507  block += bi->rowstride;
508  }
509 
510  /*
511  Calculate average color including current block.
512  */
513  avg_color_blk[0] = total_rgb_blk[0] / total_pixels_blk;
514  avg_color_blk[1] = total_rgb_blk[1] / total_pixels_blk;
515  avg_color_blk[2] = total_rgb_blk[2] / total_pixels_blk;
516 
517  /*
518  Are all the pixels within threshold of the average color?
519  */
520  is_in_range = (max_color_blk[0] - avg_color_blk[0] <= threshold &&
521  max_color_blk[1] - avg_color_blk[1] <= threshold &&
522  max_color_blk[2] - avg_color_blk[2] <= threshold &&
523  avg_color_blk[0] - min_color_blk[0] <= threshold &&
524  avg_color_blk[1] - min_color_blk[1] <= threshold &&
525  avg_color_blk[2] - min_color_blk[2] <= threshold);
526 
527  if (is_in_range) {
528  /*
529  Set the output variables to include this block.
530  */
531  min_color[0] = min_color_blk[0];
532  min_color[1] = min_color_blk[1];
533  min_color[2] = min_color_blk[2];
534  max_color[0] = max_color_blk[0];
535  max_color[1] = max_color_blk[1];
536  max_color[2] = max_color_blk[2];
537  total_rgb[0] = total_rgb_blk[0];
538  total_rgb[1] = total_rgb_blk[1];
539  total_rgb[2] = total_rgb_blk[2];
540  *total_pixels = total_pixels_blk;
541  avg_color[0] = avg_color_blk[0];
542  avg_color[1] = avg_color_blk[1];
543  avg_color[2] = avg_color_blk[2];
544  }
545 
546  return is_in_range;
547 }
548 
549 static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict)
550 {
551  BlockInfo bi;
552  int block_counter = 0;
553  int n_blocks;
554  int total_blocks;
555  int prev_block_offset;
556  int block_offset = 0;
557  uint8_t min = 0, max = 0;
558  channel_offset chan;
559  int i;
560  int tmp_min, tmp_max;
561  int total_rgb[3];
562  uint8_t avg_color[3];
563  int pixel_count;
564  uint8_t min_color[3], max_color[3];
565  double slope, y_intercept, correlation_coef;
566  const uint16_t *src_pixels = (const uint16_t *)pict->data[0];
567  uint16_t *prev_pixels = (uint16_t *)s->prev_frame->data[0];
568 
569  /* Number of 4x4 blocks in frame. */
570  total_blocks = ((s->frame_width + 3) / 4) * ((s->frame_height + 3) / 4);
571 
572  bi.image_width = s->frame_width;
573  bi.image_height = s->frame_height;
574  bi.rowstride = pict->linesize[0] / 2;
575 
576  bi.blocks_per_row = (s->frame_width + 3) / 4;
577 
578  while (block_counter < total_blocks) {
579  // SKIP CHECK
580  // make sure we have a valid previous frame and we're not writing
581  // a key frame
582  if (!s->first_frame) {
583  n_blocks = 0;
584  prev_block_offset = 0;
585 
586  while (n_blocks < 32 && block_counter + n_blocks < total_blocks) {
587 
588  block_offset = get_block_info(&bi, block_counter + n_blocks);
589 
590  // multi-block opcodes cannot span multiple rows.
591  // If we're starting a new row, break out and write the opcode
592  /* TODO: Should eventually use bi.row here to determine when a
593  row break occurs, but that is currently breaking the
594  quicktime player. This is probably due to a bug in the
595  way I'm calculating the current row.
596  */
597  if (prev_block_offset && block_offset - prev_block_offset > 12) {
598  break;
599  }
600 
601  prev_block_offset = block_offset;
602 
603  if (compare_blocks(&prev_pixels[block_offset],
604  &src_pixels[block_offset], &bi, s->skip_frame_thresh) != 0) {
605  // write out skipable blocks
606  if (n_blocks) {
607 
608  // write skip opcode
609  put_bits(&s->pb, 8, 0x80 | (n_blocks - 1));
610  block_counter += n_blocks;
611 
612  goto post_skip;
613  }
614  break;
615  }
616 
617  /*
618  * NOTE: we don't update skipped blocks in the previous frame buffer
619  * since skipped needs always to be compared against the first skipped
620  * block to avoid artifacts during gradual fade in/outs.
621  */
622 
623  // update_block_in_prev_frame(&src_pixels[block_offset],
624  // &prev_pixels[block_offset], &bi, block_counter + n_blocks);
625 
626  n_blocks++;
627  }
628 
629  // we're either at the end of the frame or we've reached the maximum
630  // of 32 blocks in a run. Write out the run.
631  if (n_blocks) {
632  // write skip opcode
633  put_bits(&s->pb, 8, 0x80 | (n_blocks - 1));
634  block_counter += n_blocks;
635 
636  continue;
637  }
638 
639  } else {
640  block_offset = get_block_info(&bi, block_counter);
641  }
642 post_skip :
643 
644  // ONE COLOR CHECK
645  if (update_block_stats(s, &bi, &src_pixels[block_offset],
646  min_color, max_color,
647  total_rgb, &pixel_count, avg_color, 1)) {
648  prev_block_offset = block_offset;
649 
650  n_blocks = 1;
651 
652  /* update this block in the previous frame buffer */
653  update_block_in_prev_frame(&src_pixels[block_offset],
654  &prev_pixels[block_offset], &bi, block_counter + n_blocks);
655 
656  // check for subsequent blocks with the same color
657  while (n_blocks < 32 && block_counter + n_blocks < total_blocks) {
658  block_offset = get_block_info(&bi, block_counter + n_blocks);
659 
660  // multi-block opcodes cannot span multiple rows.
661  // If we've hit end of a row, break out and write the opcode
662  if (block_offset - prev_block_offset > 12) {
663  break;
664  }
665 
666  if (!update_block_stats(s, &bi, &src_pixels[block_offset],
667  min_color, max_color,
668  total_rgb, &pixel_count, avg_color, 0)) {
669  break;
670  }
671 
672  prev_block_offset = block_offset;
673 
674  /* update this block in the previous frame buffer */
675  update_block_in_prev_frame(&src_pixels[block_offset],
676  &prev_pixels[block_offset], &bi, block_counter + n_blocks);
677 
678  n_blocks++;
679  }
680 
681  // write one color opcode.
682  put_bits(&s->pb, 8, 0xa0 | (n_blocks - 1));
683  // write color to encode.
684  put_bits(&s->pb, 16, rgb24_to_rgb555(avg_color));
685  // skip past the blocks we've just encoded.
686  block_counter += n_blocks;
687  } else { // FOUR COLOR CHECK
688  int err = 0;
689 
690  // get max component diff for block
691  get_max_component_diff(&bi, &src_pixels[block_offset], &min, &max, &chan);
692 
693  min_color[0] = 0;
694  max_color[0] = 0;
695  min_color[1] = 0;
696  max_color[1] = 0;
697  min_color[2] = 0;
698  max_color[2] = 0;
699 
700  // run least squares against other two components
701  for (i = 0; i < 3; i++) {
702  if (i == chan) {
703  min_color[i] = min;
704  max_color[i] = max;
705  continue;
706  }
707 
708  slope = y_intercept = correlation_coef = 0;
709 
710  if (leastsquares(&src_pixels[block_offset], &bi, chan, i,
711  &slope, &y_intercept, &correlation_coef)) {
712  min_color[i] = GET_CHAN(src_pixels[block_offset], i);
713  max_color[i] = GET_CHAN(src_pixels[block_offset], i);
714  } else {
715  tmp_min = (int)(0.5 + min * slope + y_intercept);
716  tmp_max = (int)(0.5 + max * slope + y_intercept);
717 
718  av_assert0(tmp_min <= tmp_max);
719  // clamp min and max color values
720  tmp_min = av_clip_uint8(tmp_min);
721  tmp_max = av_clip_uint8(tmp_max);
722 
723  err = FFMAX(calc_lsq_max_fit_error(&src_pixels[block_offset], &bi,
724  min, max, tmp_min, tmp_max, chan, i), err);
725 
726  min_color[i] = tmp_min;
727  max_color[i] = tmp_max;
728  }
729  }
730 
731  if (err > s->sixteen_color_thresh) { // DO SIXTEEN COLOR BLOCK
732  const uint16_t *row_ptr;
733  int rgb555;
734 
735  block_offset = get_block_info(&bi, block_counter);
736 
737  row_ptr = &src_pixels[block_offset];
738 
739  for (int y = 0; y < 4; y++) {
740  for (int x = 0; x < 4; x++){
741  rgb555 = row_ptr[x] & ~0x8000;
742 
743  put_bits(&s->pb, 16, rgb555);
744  }
745  row_ptr += bi.rowstride;
746  }
747 
748  block_counter++;
749  } else { // FOUR COLOR BLOCK
750  block_counter += encode_four_color_block(min_color, max_color,
751  &s->pb, &src_pixels[block_offset], &bi);
752  }
753 
754  /* update this block in the previous frame buffer */
755  update_block_in_prev_frame(&src_pixels[block_offset],
756  &prev_pixels[block_offset], &bi, block_counter);
757  }
758  }
759 }
760 
762 {
763  RpzaContext *s = avctx->priv_data;
764 
765  s->frame_width = avctx->width;
766  s->frame_height = avctx->height;
767 
768  s->prev_frame = av_frame_alloc();
769  if (!s->prev_frame)
770  return AVERROR(ENOMEM);
771 
772  return 0;
773 }
774 
776  const AVFrame *frame, int *got_packet)
777 {
778  RpzaContext *s = avctx->priv_data;
779  const AVFrame *pict = frame;
780  uint8_t *buf;
781  int ret = ff_alloc_packet(avctx, pkt, 6LL * avctx->height * avctx->width);
782 
783  if (ret < 0)
784  return ret;
785 
786  init_put_bits(&s->pb, pkt->data, pkt->size);
787 
788  // skip 4 byte header, write it later once the size of the chunk is known
789  put_bits32(&s->pb, 0x00);
790 
791  if (!s->prev_frame->data[0]) {
792  s->first_frame = 1;
793  s->prev_frame->format = pict->format;
794  s->prev_frame->width = pict->width;
795  s->prev_frame->height = pict->height;
796  ret = av_frame_get_buffer(s->prev_frame, 0);
797  if (ret < 0)
798  return ret;
799  } else {
800  s->first_frame = 0;
801  }
802 
803  rpza_encode_stream(s, pict);
804 
805  flush_put_bits(&s->pb);
806 
808  buf = pkt->data;
809 
810  // write header opcode
811  buf[0] = 0xe1; // chunk opcode
812 
813  // write chunk length
814  AV_WB24(buf + 1, pkt->size);
815 
816  *got_packet = 1;
817 
818  return 0;
819 }
820 
821 static int rpza_encode_end(AVCodecContext *avctx)
822 {
823  RpzaContext *s = (RpzaContext *)avctx->priv_data;
824 
825  av_frame_free(&s->prev_frame);
826 
827  return 0;
828 }
829 
830 #define OFFSET(x) offsetof(RpzaContext, x)
831 #define VE AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_ENCODING_PARAM
832 static const AVOption options[] = {
833  { "skip_frame_thresh", NULL, OFFSET(skip_frame_thresh), AV_OPT_TYPE_INT, {.i64=1}, 0, 24, VE},
834  { "start_one_color_thresh", NULL, OFFSET(start_one_color_thresh), AV_OPT_TYPE_INT, {.i64=1}, 0, 24, VE},
835  { "continue_one_color_thresh", NULL, OFFSET(continue_one_color_thresh), AV_OPT_TYPE_INT, {.i64=0}, 0, 24, VE},
836  { "sixteen_color_thresh", NULL, OFFSET(sixteen_color_thresh), AV_OPT_TYPE_INT, {.i64=1}, 0, 24, VE},
837  { NULL },
838 };
839 
840 static const AVClass rpza_class = {
841  .class_name = "rpza",
842  .item_name = av_default_item_name,
843  .option = options,
844  .version = LIBAVUTIL_VERSION_INT,
845 };
846 
848  .p.name = "rpza",
849  .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime video (RPZA)"),
850  .p.type = AVMEDIA_TYPE_VIDEO,
851  .p.id = AV_CODEC_ID_RPZA,
852  .priv_data_size = sizeof(RpzaContext),
853  .p.priv_class = &rpza_class,
854  .init = rpza_encode_init,
856  .close = rpza_encode_end,
857  .p.pix_fmts = (const enum AVPixelFormat[]) { AV_PIX_FMT_RGB555,
859 };
OFFSET
#define OFFSET(x)
Definition: rpzaenc.c:830
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:116
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:195
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:259
put_bytes_output
static int put_bytes_output(const PutBitContext *s)
Definition: put_bits.h:89
color
Definition: vf_paletteuse.c:600
rgb24_to_rgb555
static uint16_t rgb24_to_rgb555(const uint8_t *rgb24)
Definition: rpzaenc.c:138
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:116
AVFrame
This structure describes decoded (raw) audio or video data.
Definition: frame.h:325
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:397
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:34
RpzaContext::skip_frame_thresh
int skip_frame_thresh
Definition: rpzaenc.c:38
B
#define B(color)
Definition: rpzaenc.c:71
RpzaContext
Definition: rpza.c:48
FFCodec
Definition: codec_internal.h:118
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:346
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:266
rgb
Definition: rpzaenc.c:59
FFCodec::p
AVCodec p
The public AVCodec.
Definition: codec_internal.h:122
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:269
ff_rpza_encoder
const FFCodec ff_rpza_encoder
Definition: rpzaenc.c:847
BlockInfo::col
int col
Definition: rpzaenc.c:75
get_block_info
static int get_block_info(BlockInfo *bi, int block)
Definition: rpzaenc.c:116
av_frame_alloc
AVFrame * av_frame_alloc(void)
Allocate an AVFrame and set its fields to default values.
Definition: frame.c:104
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:419
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:445
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:319
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:117
rpza_encode_end
static int rpza_encode_end(AVCodecContext *avctx)
Definition: rpzaenc.c:821
rpza_encode_init
static int rpza_encode_init(AVCodecContext *avctx)
Definition: rpzaenc.c:761
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
G
#define G(color)
Definition: rpzaenc.c:70
PutBitContext
Definition: put_bits.h:50
BlockInfo::blocks_per_row
int blocks_per_row
Definition: rpzaenc.c:83
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:840
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:831
BlockInfo
Definition: dvdec.c:56
AVPacket::size
int size
Definition: packet.h:375
NULL_IF_CONFIG_SMALL
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
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:412
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:360
compare_blocks
static int compare_blocks(const uint16_t *block1, const uint16_t *block2, const BlockInfo *bi, int thresh)
Definition: rpzaenc.c:245
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:171
common.h
AV_PIX_FMT_RGB555
#define AV_PIX_FMT_RGB555
Definition: pixfmt.h:396
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:211
AVCodecContext::height
int height
Definition: avcodec.h:571
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
frame
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several the filter must be ready for frames arriving randomly on any input any filter with several inputs will most likely require some kind of queuing mechanism It is perfectly acceptable to have a limited queue and to drop frames when the inputs are too unbalanced request_frame For filters that do not use the this method is called when a frame is wanted on an output For a it should directly call filter_frame on the corresponding output For a if there are queued frames already one of these frames should be pushed If the filter should request a frame on one of its repeatedly until at least one frame has been pushed Return or at least make progress towards producing a frame
Definition: filter_design.txt:264
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:387
AVCodecContext
main external API structure.
Definition: avcodec.h:398
AVFrame::height
int height
Definition: frame.h:397
BlockInfo::total_blocks
int total_blocks
Definition: rpzaenc.c:84
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:87
options
static const AVOption options[]
Definition: rpzaenc.c:832
BlockInfo::block_width
int block_width
Definition: rpzaenc.c:76
av_clip_uint8
#define av_clip_uint8
Definition: common.h:101
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:92
diff_colors
static int diff_colors(const uint8_t *colorA, const uint8_t *colorB)
Definition: rpzaenc.c:157
flush_put_bits
static void flush_put_bits(PutBitContext *s)
Pad the end of the output stream with zeros.
Definition: put_bits.h:143
diff
static av_always_inline int diff(const uint32_t a, const uint32_t b)
Definition: vf_palettegen.c:139
AVPacket
This structure stores compressed data.
Definition: packet.h:351
AVCodecContext::priv_data
void * priv_data
Definition: avcodec.h:425
AVCodecContext::width
int width
picture width / height.
Definition: avcodec.h:571
R
#define R(color)
Definition: rpzaenc.c:69
rpza_encode_stream
static void rpza_encode_stream(RpzaContext *s, const AVFrame *pict)
Definition: rpzaenc.c:549
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:370
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:155
put_bits.h
rpza_encode_frame
static int rpza_encode_frame(AVCodecContext *avctx, AVPacket *pkt, const AVFrame *frame, int *got_packet)
Definition: rpzaenc.c:775
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