2 * Interplay MVE video encoder (8 bit)
3 * Copyright (C) 2006 Jens Granseuer <jensgr@gmx.net>
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
29 #include "gstmvemux.h"
31 typedef struct _GstMveEncoderData GstMveEncoderData;
32 typedef struct _GstMveEncoding GstMveEncoding;
33 typedef struct _GstMveApprox GstMveApprox;
34 typedef struct _GstMveQuant GstMveQuant;
36 #define MVE_RMASK 0x00ff0000
37 #define MVE_GMASK 0x0000ff00
38 #define MVE_BMASK 0x000000ff
43 #define MVE_RVAL(p) (((p) & MVE_RMASK) >> MVE_RSHIFT)
44 #define MVE_GVAL(p) (((p) & MVE_GMASK) >> MVE_GSHIFT)
45 #define MVE_BVAL(p) (((p) & MVE_BMASK) >> MVE_BSHIFT)
46 #define MVE_COL(r,g,b) (((r) << MVE_RSHIFT) | ((g) << MVE_GSHIFT) | ((b) << MVE_BSHIFT))
48 struct _GstMveEncoderData
51 /* current position in frame */
54 /* palette for current frame */
55 const guint32 *palette;
57 /* commonly used quantization results
58 (2 and 4 colors) for the current block */
70 struct _GstMveEncoding
74 guint32 (*approx) (GstMveEncoderData * enc, const guint8 * src,
78 #define MVE_APPROX_MAX_ERROR G_MAXUINT32
84 guint8 data[64]; /* max 64 bytes encoded per block */
85 guint8 block[64]; /* block in final image */
91 guint16 r_total, g_total, b_total;
93 guint8 hits, hits_last;
98 #define mve_median(mve, src) mve_median_sub ((mve), (src), 8, 8, 0)
99 #define mve_color_dist(c1, c2) \
100 mve_color_dist_rgb (MVE_RVAL (c1), MVE_GVAL (c1), MVE_BVAL (c1), \
101 MVE_RVAL (c2), MVE_GVAL (c2), MVE_BVAL (c2));
102 #define mve_color_dist2(c, r, g, b) \
103 mve_color_dist_rgb (MVE_RVAL (c), MVE_GVAL (c), MVE_BVAL (c), (r), (g), (b))
106 /* comparison function for qsort() */
108 mve_comp_solution (const void *a, const void *b)
110 const GArray *aa = *((GArray **) a);
111 const GArray *bb = *((GArray **) b);
115 else if (bb->len <= 1)
118 return g_array_index (aa, GstMveApprox, aa->len - 2).error -
119 g_array_index (bb, GstMveApprox, bb->len - 2).error;
122 static inline guint32
123 mve_color_dist_rgb (guint8 r1, guint8 g1, guint8 b1,
124 guint8 r2, guint8 g2, guint8 b2)
126 /* euclidean distance (minus sqrt) */
131 return dr * dr + dg * dg + db * db;
135 mve_find_pal_color (const guint32 * pal, guint32 col)
137 /* find the closest matching color in the palette */
140 const guint8 r = MVE_RVAL (col), g = MVE_GVAL (col), b = MVE_BVAL (col);
141 guint32 ebest = MVE_APPROX_MAX_ERROR;
143 for (i = 0; i < MVE_PALETTE_COUNT; ++i, ++pal) {
144 guint32 e = mve_color_dist2 (*pal, r, g, b);
159 mve_find_pal_color2 (const guint32 * pal, const guint8 * subset, guint32 col,
162 /* find the closest matching color in the partial indexed palette */
165 const guint8 r = MVE_RVAL (col), g = MVE_GVAL (col), b = MVE_BVAL (col);
166 guint32 ebest = MVE_APPROX_MAX_ERROR;
168 for (i = 0; i < size; ++i) {
169 guint32 e = mve_color_dist2 (pal[subset[i]], r, g, b);
184 mve_map_to_palette (const GstMveEncoderData * enc, const guint8 * colors,
185 const guint8 * data, guint8 * dest, guint w, guint h, guint ncols)
189 for (y = 0; y < h; ++y) {
190 for (x = 0; x < w; ++x) {
192 mve_find_pal_color2 (enc->palette, colors, enc->palette[data[x]],
195 data += enc->mve->width;
200 /* compute average color in a sub-block */
202 mve_median_sub (const GstMveEncoderData * enc, const guint8 * src, guint w,
206 const guint max = w * h, max2 = max >> 1;
207 guint32 r_total = max2, g_total = max2, b_total = max2;
209 src += ((n * w) % 8) + (((n * (8 - h)) / (12 - w)) * h * enc->mve->width);
211 for (y = 0; y < h; ++y) {
212 for (x = 0; x < w; ++x) {
213 guint32 p = enc->palette[src[x]];
215 r_total += MVE_RVAL (p);
216 g_total += MVE_GVAL (p);
217 b_total += MVE_BVAL (p);
219 src += enc->mve->width;
222 return mve_find_pal_color (enc->palette,
223 MVE_COL (r_total / max, g_total / max, b_total / max));
227 mve_quant_init (const GstMveEncoderData * enc, GstMveQuant * q,
228 guint n_clusters, const guint8 * data, guint w, guint h)
235 /* init first cluster with lowest (darkest), second with highest (lightest)
236 color. if we need 4 clusters, fill in first and last color in the block
237 and hope they make for a good distribution */
238 cols[0] = cols[1] = cols[2] = enc->palette[data[0]];
239 cols[3] = enc->palette[data[(h - 1) * enc->mve->width + w - 1]];
241 /* favour red over green and blue */
243 (MVE_RVAL (cols[0]) << 1) + MVE_GVAL (cols[0]) + MVE_BVAL (cols[0]);
245 for (y = 0; y < h; ++y) {
246 for (x = 0; x < w; ++x) {
247 guint32 c = enc->palette[data[x]];
249 if ((c != cols[0]) && (c != cols[1])) {
250 guint v = (MVE_RVAL (c) << 1) + MVE_GVAL (c) + MVE_BVAL (c);
255 } else if (v > val[1]) {
261 data += enc->mve->width;
264 for (i = 0; i < n_clusters; ++i) {
266 q[i].r = MVE_RVAL (cols[i]);
267 q[i].g = MVE_GVAL (cols[i]);
268 q[i].b = MVE_BVAL (cols[i]);
269 q[i].r_total = q[i].g_total = q[i].b_total = 0;
270 q[i].hits = q[i].hits_last = 0;
277 mve_quant_update_clusters (GstMveQuant * q, guint n_clusters)
279 gboolean changed = FALSE;
282 for (i = 0; i < n_clusters; ++i) {
284 guint32 means = MVE_COL ((q[i].r_total + q[i].hits / 2) / q[i].hits,
285 (q[i].g_total + q[i].hits / 2) / q[i].hits,
286 (q[i].b_total + q[i].hits / 2) / q[i].hits);
288 if ((means != q[i].col) || (q[i].hits != q[i].hits_last))
292 q[i].r_total = q[i].g_total = q[i].b_total = 0;
296 GstMveQuant *worst = NULL;
298 /* try to replace unused cluster with a better representative */
299 for (j = 0; j < n_clusters; ++j) {
300 if (q[j].max_error > max_err) {
302 max_err = worst->max_error;
306 q[i].col = worst->max_miss;
307 worst->max_error = 0;
312 q[i].r = MVE_RVAL (q[i].col);
313 q[i].g = MVE_GVAL (q[i].col);
314 q[i].b = MVE_BVAL (q[i].col);
315 q[i].hits_last = q[i].hits;
318 for (i = 0; i < n_clusters; ++i) {
325 /* quantize a sub-block using a k-means algorithm */
327 mve_quantize (const GstMveEncoderData * enc, const guint8 * src,
328 guint w, guint h, guint n, guint ncols, guint8 * dest, guint8 * cols)
335 g_assert (n <= 4 && ncols <= 4);
337 src += ((n * w) % 8) + (((n * (8 - h)) / (12 - w)) * h * enc->mve->width);
338 dest += ((n * w) % 8) + (((n * (8 - h)) / (12 - w)) * h * 8);
340 mve_quant_init (enc, q, ncols, src, w, h);
346 /* for each pixel find the closest cluster */
347 for (y = 0; y < h; ++y) {
348 for (x = 0; x < w; ++x) {
349 guint32 c = enc->palette[data[x]];
350 guint8 r = MVE_RVAL (c), g = MVE_GVAL (c), b = MVE_BVAL (c);
351 guint32 minerr = MVE_APPROX_MAX_ERROR, err;
352 GstMveQuant *best = NULL;
354 for (i = 0; i < ncols; ++i) {
355 err = mve_color_dist_rgb (r, g, b, q[i].r, q[i].g, q[i].b);
368 if (minerr > best->max_error) {
369 best->max_error = minerr;
375 data += enc->mve->width;
377 } while (mve_quant_update_clusters (q, ncols));
379 /* fill cols array with result colors */
380 for (i = 0; i < ncols; ++i)
381 cols[i] = mve_find_pal_color (enc->palette, q[i].col);
383 /* make sure we have unique colors in slots 0/1 and 2/3 */
384 if (cols[0] == cols[1])
386 if ((ncols > 2) && (cols[2] == cols[3]))
389 /* generate the resulting quantized block */
390 mve_map_to_palette (enc, cols, src, dest, w, h, ncols);
396 mve_block_error (const GstMveEncoderData * enc, const guint8 * b1,
397 const guint8 * b2, guint32 threshold)
399 /* compute error between two blocks in a frame */
403 for (y = 0; y < 8; ++y) {
404 for (x = 0; x < 8; ++x) {
405 e += mve_color_dist (enc->palette[*b1], enc->palette[*b2]);
407 /* using a threshold to return early gives a huge performance bonus */
409 return MVE_APPROX_MAX_ERROR;
414 b1 += enc->mve->width - 8;
415 b2 += enc->mve->width - 8;
422 mve_block_error_packed (const GstMveEncoderData * enc, const guint8 * block,
423 const guint8 * scratch)
425 /* compute error between a block in a frame and a (continuous) scratch pad */
429 for (y = 0; y < 8; ++y) {
430 for (x = 0; x < 8; ++x) {
431 guint32 c1 = enc->palette[block[x]], c2 = enc->palette[scratch[x]];
433 e += mve_color_dist (c1, c2);
435 block += enc->mve->width;
443 mve_store_block (const GstMveMux * mve, const guint8 * block, guint8 * scratch)
445 /* copy block from frame to a (continuous) scratch pad */
448 for (y = 0; y < 8; ++y) {
449 memcpy (scratch, block, 8);
456 mve_restore_block (const GstMveMux * mve, guint8 * block,
457 const guint8 * scratch)
459 /* copy block from scratch pad to frame */
462 for (y = 0; y < 8; ++y) {
463 memcpy (block, scratch, 8);
471 mve_try_vector (GstMveEncoderData * enc, const guint8 * src,
472 const guint8 * frame, gint pn, GstMveApprox * apx)
474 /* try to locate a similar 8x8 block in the given frame using a motion vector */
480 apx->error = MVE_APPROX_MAX_ERROR;
482 for (i = 0; i < 256; ++i) {
487 dx = -14 + ((i - 56) % 29);
488 dy = 8 + ((i - 56) / 29);
491 fx = enc->x + dx * pn;
492 fy = enc->y + dy * pn;
494 if ((fx >= 0) && (fy >= 0) && (fx + 8 <= enc->mve->width)
495 && (fy + 8 <= enc->mve->height)) {
497 mve_block_error (enc, src, frame + fy * enc->mve->width + fx,
499 if (err < apx->error) {
501 mve_store_block (enc->mve, frame + fy * enc->mve->width + fx,
514 mve_encode_0x0 (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
516 /* copy a block from the last frame (0 bytes) */
517 if (enc->mve->last_frame == NULL)
518 return MVE_APPROX_MAX_ERROR;
520 mve_store_block (enc->mve,
521 GST_BUFFER_DATA (enc->mve->last_frame) +
522 enc->y * enc->mve->width + enc->x, apx->block);
523 apx->error = mve_block_error_packed (enc, src, apx->block);
528 mve_encode_0x1 (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
530 /* copy a block from the second to last frame (0 bytes) */
531 if (enc->mve->second_last_frame == NULL)
532 return MVE_APPROX_MAX_ERROR;
534 mve_store_block (enc->mve,
535 GST_BUFFER_DATA (enc->mve->second_last_frame) +
536 enc->y * enc->mve->width + enc->x, apx->block);
537 apx->error = mve_block_error_packed (enc, src, apx->block);
542 mve_encode_0x2 (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
544 /* copy block from 2 frames ago using a motion vector (1 byte) */
545 if (enc->mve->quick_encoding || enc->mve->second_last_frame == NULL)
546 return MVE_APPROX_MAX_ERROR;
548 apx->error = mve_try_vector (enc, src,
549 GST_BUFFER_DATA (enc->mve->second_last_frame), 1, apx);
554 mve_encode_0x3 (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
556 /* copy 8x8 block from current frame from an up/left block (1 byte) */
557 if (enc->mve->quick_encoding)
558 return MVE_APPROX_MAX_ERROR;
560 apx->error = mve_try_vector (enc, src,
561 src - enc->mve->width * enc->y - enc->x, -1, apx);
567 mve_encode_0x4 (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
569 /* copy a block from previous frame using a motion vector (-8/-8 to +7/+7) (1 byte) */
570 const GstMveMux *mve = enc->mve;
573 gint x1, x2, xi, y1, y2, yi;
575 if (mve->last_frame == NULL)
576 return MVE_APPROX_MAX_ERROR;
578 frame = GST_BUFFER_DATA (mve->last_frame);
584 else if (x2 + 8 > mve->width)
591 else if (y2 + 8 > mve->height)
592 y2 = mve->height - 8;
594 apx->error = MVE_APPROX_MAX_ERROR;
596 for (yi = y1; yi <= y2; ++yi) {
597 guint yoff = yi * mve->width;
599 for (xi = x1; xi <= x2; ++xi) {
600 err = mve_block_error (enc, src, frame + yoff + xi, apx->error);
601 if (err < apx->error) {
602 apx->data[0] = ((xi - enc->x + 8) & 0xF) | ((yi - enc->y + 8) << 4);
603 mve_store_block (mve, frame + yoff + xi, apx->block);
615 mve_encode_0x5 (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
617 /* copy a block from previous frame using a motion vector
618 (-128/-128 to +127/+127) (2 bytes) */
619 const GstMveMux *mve = enc->mve;
622 gint x1, x2, xi, y1, y2, yi;
624 if (mve->quick_encoding || mve->last_frame == NULL)
625 return MVE_APPROX_MAX_ERROR;
627 frame = GST_BUFFER_DATA (mve->last_frame);
633 if (x2 + 8 > mve->width)
640 if (y2 + 8 > mve->height)
641 y2 = mve->height - 8;
643 apx->error = MVE_APPROX_MAX_ERROR;
645 for (yi = y1; yi <= y2; ++yi) {
646 gint yoff = yi * mve->width;
648 for (xi = x1; xi <= x2; ++xi) {
649 err = mve_block_error (enc, src, frame + yoff + xi, apx->error);
650 if (err < apx->error) {
651 apx->data[0] = xi - enc->x;
652 apx->data[1] = yi - enc->y;
653 mve_store_block (mve, frame + yoff + xi, apx->block);
665 mve_encode_0x7a (GstMveEncoderData * enc, const guint8 * src,
668 /* 2-color encoding for 2x2 solid blocks (4 bytes) */
673 guint8 r[2], g[2], b[2], rb, gb, bb;
674 guint8 *block = apx->block;
675 guint16 mask = 0x0001;
678 /* calculate mean colors for the entire block */
679 if (!enc->q2available) {
681 mve_quantize (enc, src, 8, 8, 0, 2, enc->q2block, enc->q2colors);
682 enc->q2available = TRUE;
686 apx->data[0] = MAX (enc->q2colors[0], enc->q2colors[1]);
687 apx->data[1] = MIN (enc->q2colors[0], enc->q2colors[1]);
689 for (x = 0; x < 2; ++x) {
690 r[x] = MVE_RVAL (enc->palette[apx->data[x]]);
691 g[x] = MVE_GVAL (enc->palette[apx->data[x]]);
692 b[x] = MVE_BVAL (enc->palette[apx->data[x]]);
695 /* calculate mean colors for each 2x2 block and map to global colors */
696 for (y = 0; y < 4; ++y) {
697 for (x = 0; x < 4; ++x, mask <<= 1) {
698 pix[0] = enc->palette[src[0]];
699 pix[1] = enc->palette[src[1]];
700 pix[2] = enc->palette[src[enc->mve->width]];
701 pix[3] = enc->palette[src[enc->mve->width + 1]];
703 rb = (MVE_RVAL (pix[0]) + MVE_RVAL (pix[1]) + MVE_RVAL (pix[2]) +
704 MVE_RVAL (pix[3]) + 2) / 4;
705 gb = (MVE_GVAL (pix[0]) + MVE_GVAL (pix[1]) + MVE_GVAL (pix[2]) +
706 MVE_GVAL (pix[3]) + 2) / 4;
707 bb = (MVE_BVAL (pix[0]) + MVE_BVAL (pix[1]) + MVE_BVAL (pix[2]) +
708 MVE_BVAL (pix[3]) + 2) / 4;
710 e1 = mve_color_dist_rgb (rb, gb, bb, r[0], g[0], b[0]);
711 e2 = mve_color_dist_rgb (rb, gb, bb, r[1], g[1], b[1]);
720 block[0] = block[1] = block[8] = block[9] = mean;
725 src += (enc->mve->width * 2) - 8;
729 apx->data[2] = flags & 0x00FF;
730 apx->data[3] = (flags & 0xFF00) >> 8;
733 mve_block_error_packed (enc, src - enc->mve->width * 8, apx->block);
738 mve_encode_0x7b (GstMveEncoderData * enc, const guint8 * src,
741 /* generic 2-color encoding (10 bytes) */
743 guint8 *data = apx->data;
744 guint8 *block = apx->block;
746 if (!enc->q2available) {
748 mve_quantize (enc, src, 8, 8, 0, 2, enc->q2block, enc->q2colors);
749 enc->q2available = TRUE;
752 memcpy (block, enc->q2block, 64);
755 data[0] = MIN (enc->q2colors[0], enc->q2colors[1]);
756 data[1] = MAX (enc->q2colors[0], enc->q2colors[1]);
759 for (y = 0; y < 8; ++y) {
762 for (x = 0x01; x <= 0x80; x <<= 1) {
763 if (*block == apx->data[1])
770 apx->error = enc->q2error;
775 mve_encode_0x8a (GstMveEncoderData * enc, const guint8 * src,
778 /* 2-color encoding for top and bottom half (12 bytes) */
781 guint i, x, y, shifter;
782 guint8 *block = apx->block;
783 guint8 *data = apx->data;
787 for (i = 0; i < 2; ++i) {
788 apx->error += mve_quantize (enc, src, 8, 4, i, 2, apx->block, cols);
793 /* p0 > p1 && p2 > p3 */
794 data[0] = MAX (cols[0], cols[1]);
795 data[1] = MIN (cols[0], cols[1]);
797 for (y = 0; y < 4; ++y) {
798 for (x = 0; x < 8; ++x, ++shifter) {
799 if (block[x] == data[1])
800 flags |= 1 << shifter;
804 data[2] = flags & 0x000000FF;
805 data[3] = (flags & 0x0000FF00) >> 8;
806 data[4] = (flags & 0x00FF0000) >> 16;
807 data[5] = (flags & 0xFF000000) >> 24;
815 mve_encode_0x8b (GstMveEncoderData * enc, const guint8 * src,
818 /* 2-color encoding for left and right half (12 bytes) */
821 guint i, x, y, shifter;
822 guint8 *block = apx->block;
823 guint8 *data = apx->data;
827 for (i = 0; i < 2; ++i) {
828 apx->error += mve_quantize (enc, src, 4, 8, i, 2, apx->block, cols);
833 /* p0 > p1 && p2 <= p3 */
834 data[i] = MAX (cols[0], cols[1]);
835 data[i ^ 1] = MIN (cols[0], cols[1]);
837 for (y = 0; y < 8; ++y) {
838 for (x = 0; x < 4; ++x, ++shifter) {
839 if (block[x] == data[1])
840 flags |= 1 << shifter;
845 data[2] = flags & 0x000000FF;
846 data[3] = (flags & 0x0000FF00) >> 8;
847 data[4] = (flags & 0x00FF0000) >> 16;
848 data[5] = (flags & 0xFF000000) >> 24;
850 block = apx->block + 4;
857 mve_encode_0x8c (GstMveEncoderData * enc, const guint8 * src,
860 /* 2-color encoding for each 4x4 quadrant (16 bytes) */
863 guint i, x, y, shifter;
865 guint8 *data = apx->data;
869 for (i = 0; i < 4; ++i) {
871 mve_quantize (enc, src, 4, 4, ((i & 1) << 1) | ((i & 2) >> 1), 2,
876 data[0] = MIN (cols[0], cols[1]);
877 data[1] = MAX (cols[0], cols[1]);
883 block = apx->block + ((i / 2) * 4) + ((i % 2) * 32);
887 for (y = 0; y < 4; ++y) {
888 for (x = 0; x < 4; ++x, ++shifter) {
889 if (block[x] == data[1])
890 flags |= 1 << shifter;
895 data[2] = flags & 0x00FF;
896 data[3] = (flags & 0xFF00) >> 8;
904 mve_encode_0x9a (GstMveEncoderData * enc, const guint8 * src,
907 /* 4-color encoding for 2x2 solid blocks (8 bytes) */
910 guint i, x, y, mean = 0;
911 guint8 r[4], g[4], b[4], rb, gb, bb;
912 guint8 *block = apx->block;
916 /* calculate mean colors for the entire block */
917 if (!enc->q4available) {
919 mve_quantize (enc, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
920 enc->q4available = TRUE;
923 /* p0 <= p1 && p2 > p3 */
924 apx->data[0] = MIN (enc->q4colors[0], enc->q4colors[1]);
925 apx->data[1] = MAX (enc->q4colors[0], enc->q4colors[1]);
926 apx->data[2] = MAX (enc->q4colors[2], enc->q4colors[3]);
927 apx->data[3] = MIN (enc->q4colors[2], enc->q4colors[3]);
929 for (i = 0; i < 4; ++i) {
930 r[i] = MVE_RVAL (enc->palette[apx->data[i]]);
931 g[i] = MVE_GVAL (enc->palette[apx->data[i]]);
932 b[i] = MVE_BVAL (enc->palette[apx->data[i]]);
935 /* calculate mean colors for each 2x2 block and map to global colors */
936 for (y = 0; y < 4; ++y) {
937 for (x = 0; x < 4; ++x, shifter += 2) {
938 p[0] = enc->palette[src[0]];
939 p[1] = enc->palette[src[1]];
940 p[2] = enc->palette[src[enc->mve->width]];
941 p[3] = enc->palette[src[enc->mve->width + 1]];
943 rb = (MVE_RVAL (p[0]) + MVE_RVAL (p[1]) + MVE_RVAL (p[2]) +
944 MVE_RVAL (p[3]) + 2) / 4;
945 gb = (MVE_GVAL (p[0]) + MVE_GVAL (p[1]) + MVE_GVAL (p[2]) +
946 MVE_GVAL (p[3]) + 2) / 4;
947 bb = (MVE_BVAL (p[0]) + MVE_BVAL (p[1]) + MVE_BVAL (p[2]) +
948 MVE_BVAL (p[3]) + 2) / 4;
950 emin = MVE_APPROX_MAX_ERROR;
951 for (i = 0; i < 4; ++i) {
952 e = mve_color_dist_rgb (rb, gb, bb, r[i], g[i], b[i]);
959 flags |= mean << shifter;
960 block[0] = block[1] = block[8] = block[9] = apx->data[mean];
965 src += (enc->mve->width * 2) - 8;
969 apx->data[4] = flags & 0x000000FF;
970 apx->data[5] = (flags & 0x0000FF00) >> 8;
971 apx->data[6] = (flags & 0x00FF0000) >> 16;
972 apx->data[7] = (flags & 0xFF000000) >> 24;
975 mve_block_error_packed (enc, src - 8 * enc->mve->width, apx->block);
980 mve_encode_0x9b (GstMveEncoderData * enc, const guint8 * src,
983 /* 4-color encoding for 2x1 solid blocks (12 bytes) */
986 guint i, x, y, mean = 0;
987 guint8 r[4], g[4], b[4], rb, gb, bb;
988 guint8 *data = apx->data;
989 guint8 *block = apx->block;
993 /* calculate mean colors for the entire block */
994 if (!enc->q4available) {
996 mve_quantize (enc, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
997 enc->q4available = TRUE;
1000 /* p0 > p1 && p2 <= p3 */
1001 data[0] = MAX (enc->q4colors[0], enc->q4colors[1]);
1002 data[1] = MIN (enc->q4colors[0], enc->q4colors[1]);
1003 data[2] = MIN (enc->q4colors[2], enc->q4colors[3]);
1004 data[3] = MAX (enc->q4colors[2], enc->q4colors[3]);
1006 for (i = 0; i < 4; ++i) {
1007 r[i] = MVE_RVAL (enc->palette[data[i]]);
1008 g[i] = MVE_GVAL (enc->palette[data[i]]);
1009 b[i] = MVE_BVAL (enc->palette[data[i]]);
1013 /* calculate mean colors for each 2x1 block and map to global colors */
1014 for (y = 0; y < 8; ++y) {
1015 for (x = 0; x < 4; ++x, shifter += 2) {
1016 p[0] = enc->palette[src[0]];
1017 p[1] = enc->palette[src[1]];
1018 rb = (MVE_RVAL (p[0]) + MVE_RVAL (p[1]) + 1) / 2;
1019 gb = (MVE_GVAL (p[0]) + MVE_GVAL (p[1]) + 1) / 2;
1020 bb = (MVE_BVAL (p[0]) + MVE_BVAL (p[1]) + 1) / 2;
1022 emin = MVE_APPROX_MAX_ERROR;
1023 for (i = 0; i < 4; ++i) {
1024 e = mve_color_dist_rgb (rb, gb, bb, r[i], g[i], b[i]);
1031 flags |= mean << shifter;
1032 block[0] = block[1] = apx->data[mean];
1038 if ((y == 3) || (y == 7)) {
1039 data[0] = flags & 0x000000FF;
1040 data[1] = (flags & 0x0000FF00) >> 8;
1041 data[2] = (flags & 0x00FF0000) >> 16;
1042 data[3] = (flags & 0xFF000000) >> 24;
1049 src += enc->mve->width - 8;
1053 mve_block_error_packed (enc, src - 8 * enc->mve->width, apx->block);
1058 mve_encode_0x9c (GstMveEncoderData * enc, const guint8 * src,
1061 /* 4-color encoding for 1x2 solid blocks (12 bytes) */
1064 guint i, x, y, mean = 0;
1065 guint8 r[4], g[4], b[4], rb, gb, bb;
1066 guint8 *data = apx->data;
1067 guint8 *block = apx->block;
1071 /* calculate mean colors for the entire block */
1072 if (!enc->q4available) {
1074 mve_quantize (enc, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
1075 enc->q4available = TRUE;
1078 /* p0 > p1 && p2 > p3 */
1079 data[0] = MAX (enc->q4colors[0], enc->q4colors[1]);
1080 data[1] = MIN (enc->q4colors[0], enc->q4colors[1]);
1081 data[2] = MAX (enc->q4colors[2], enc->q4colors[3]);
1082 data[3] = MIN (enc->q4colors[2], enc->q4colors[3]);
1084 for (i = 0; i < 4; ++i) {
1085 r[i] = MVE_RVAL (enc->palette[data[i]]);
1086 g[i] = MVE_GVAL (enc->palette[data[i]]);
1087 b[i] = MVE_BVAL (enc->palette[data[i]]);
1091 /* calculate mean colors for each 1x2 block and map to global colors */
1092 for (y = 0; y < 4; ++y) {
1093 for (x = 0; x < 8; ++x, shifter += 2) {
1094 p[0] = enc->palette[src[0]];
1095 p[1] = enc->palette[src[enc->mve->width]];
1096 rb = (MVE_RVAL (p[0]) + MVE_RVAL (p[1]) + 1) / 2;
1097 gb = (MVE_GVAL (p[0]) + MVE_GVAL (p[1]) + 1) / 2;
1098 bb = (MVE_BVAL (p[0]) + MVE_BVAL (p[1]) + 1) / 2;
1100 emin = MVE_APPROX_MAX_ERROR;
1101 for (i = 0; i < 4; ++i) {
1102 e = mve_color_dist_rgb (rb, gb, bb, r[i], g[i], b[i]);
1109 flags |= mean << shifter;
1110 block[0] = block[8] = apx->data[mean];
1116 if ((y == 1) || (y == 3)) {
1117 data[0] = flags & 0x000000FF;
1118 data[1] = (flags & 0x0000FF00) >> 8;
1119 data[2] = (flags & 0x00FF0000) >> 16;
1120 data[3] = (flags & 0xFF000000) >> 24;
1127 src += (enc->mve->width * 2) - 8;
1132 mve_block_error_packed (enc, src - 8 * enc->mve->width, apx->block);
1137 mve_encode_0x9d (GstMveEncoderData * enc, const guint8 * src,
1140 /* generic 4-color encoding (20 bytes) */
1144 guint8 *data = apx->data;
1145 guint8 *block = apx->block;
1147 if (!enc->q4available) {
1149 mve_quantize (enc, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
1150 enc->q4available = TRUE;
1153 memcpy (block, enc->q4block, 64);
1155 /* p0 <= p1 && p2 <= p3 */
1156 data[0] = MIN (enc->q4colors[0], enc->q4colors[1]);
1157 data[1] = MAX (enc->q4colors[0], enc->q4colors[1]);
1158 data[2] = MIN (enc->q4colors[2], enc->q4colors[3]);
1159 data[3] = MAX (enc->q4colors[2], enc->q4colors[3]);
1162 for (y = 0; y < 8; ++y) {
1163 for (x = 0; x < 8; ++x, shifter += 2) {
1165 for (i = 0; i < 3; ++i) {
1166 if (*block == apx->data[i])
1170 flags |= i << shifter;
1174 data[0] = flags & 0x000000FF;
1175 data[1] = (flags & 0x0000FF00) >> 8;
1181 apx->error = enc->q4error;
1186 mve_encode_0xaa (GstMveEncoderData * enc, const guint8 * src,
1189 /* 4-color encoding for top and bottom half (24 bytes) */
1192 guint i, j, x, y, shifter;
1193 guint8 *block = apx->block;
1194 guint8 *data = apx->data;
1199 for (i = 0; i < 2; ++i) {
1200 apx->error += mve_quantize (enc, src, 8, 4, i, 4, apx->block, cols);
1205 /* p0 > p1 && p4 > p5 */
1206 data[0] = MAX (cols[0], cols[1]);
1207 data[1] = MIN (cols[0], cols[1]);
1213 for (y = 0; y < 4; ++y) {
1214 for (x = 0; x < 8; ++x, shifter += 2) {
1215 for (j = 0; j < 3; ++j) {
1216 if (block[x] == p[j])
1219 flags |= j << shifter;
1223 if ((y == 1) || (y == 3)) {
1224 data[0] = flags & 0x000000FF;
1225 data[1] = (flags & 0x0000FF00) >> 8;
1226 data[2] = (flags & 0x00FF0000) >> 16;
1227 data[3] = (flags & 0xFF000000) >> 24;
1239 mve_encode_0xab (GstMveEncoderData * enc, const guint8 * src,
1242 /* 4-color encoding for left and right half (24 bytes) */
1245 guint i, j, x, y, shifter;
1246 guint8 *block = apx->block;
1247 guint8 *data = apx->data;
1252 for (i = 0; i < 2; ++i) {
1253 apx->error += mve_quantize (enc, src, 4, 8, i, 4, apx->block, cols);
1258 /* p0 > p1 && p4 <= p5 */
1259 data[i] = MAX (cols[0], cols[1]);
1260 data[i ^ 1] = MIN (cols[0], cols[1]);
1266 for (y = 0; y < 8; ++y) {
1267 for (x = 0; x < 4; ++x, shifter += 2) {
1268 for (j = 0; j < 3; ++j) {
1269 if (block[x] == p[j])
1272 flags |= j << shifter;
1276 if ((y == 3) || (y == 7)) {
1277 data[0] = flags & 0x000000FF;
1278 data[1] = (flags & 0x0000FF00) >> 8;
1279 data[2] = (flags & 0x00FF0000) >> 16;
1280 data[3] = (flags & 0xFF000000) >> 24;
1286 block = apx->block + 4;
1293 mve_encode_0xac (GstMveEncoderData * enc, const guint8 * src,
1296 /* 4-color encoding for each 4x4 quadrant (32 bytes) */
1299 guint i, j, x, y, shifter;
1301 guint8 *data = apx->data;
1305 for (i = 0; i < 4; ++i) {
1307 mve_quantize (enc, src, 4, 4, ((i & 1) << 1) | ((i & 2) >> 1), 4,
1311 data[0] = MIN (cols[0], cols[1]);
1312 data[1] = MAX (cols[0], cols[1]);
1316 block = apx->block + ((i / 2) * 4) + ((i % 2) * 32);
1320 for (y = 0; y < 4; ++y) {
1321 for (x = 0; x < 4; ++x, shifter += 2) {
1322 for (j = 0; j < 3; ++j) {
1323 if (block[x] == data[j])
1326 flags |= j << shifter;
1331 data[4] = flags & 0x000000FF;
1332 data[5] = (flags & 0x0000FF00) >> 8;
1333 data[6] = (flags & 0x00FF0000) >> 16;
1334 data[7] = (flags & 0xFF000000) >> 24;
1342 mve_encode_0xb (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
1344 /* 64-color encoding (each pixel in block is a different color) (64 bytes) */
1345 mve_store_block (enc->mve, src, apx->block);
1346 memcpy (apx->data, apx->block, 64);
1353 mve_encode_0xc (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
1355 /* 16-color block encoding: each 2x2 block is a different color (16 bytes) */
1357 const guint w = enc->mve->width;
1360 /* calculate median color for each 2x2 block */
1361 for (y = 0; y < 4; ++y) {
1362 for (x = 0; x < 4; ++x) {
1363 guint32 p = enc->palette[src[0]];
1365 r = MVE_RVAL (p) + 2;
1366 g = MVE_GVAL (p) + 2;
1367 b = MVE_BVAL (p) + 2;
1369 p = enc->palette[src[1]];
1374 p = enc->palette[src[w]];
1379 p = enc->palette[src[w + 1]];
1384 apx->block[i] = apx->block[i + 1] = apx->block[i + 2] =
1385 apx->block[i + 3] = apx->data[i >> 2] =
1386 mve_find_pal_color (enc->palette, MVE_COL (r >> 2, g >> 2, b >> 2));
1394 apx->error = mve_block_error_packed (enc, src - (8 * w), apx->block);
1399 mve_encode_0xd (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
1401 /* 4-color block encoding: each 4x4 block is a different color (4 bytes) */
1404 /* calculate median color for each 4x4 block */
1405 for (i = 0; i < 4; ++i) {
1407 mve_median_sub (enc, src, 4, 4, ((i & 1) << 1) | ((i & 2) >> 1));
1408 guint8 *block = apx->block + ((i / 2) * 4) + ((i % 2) * 32);
1410 for (y = 0; y < 4; ++y) {
1411 memset (block, median, 4);
1415 apx->data[i] = median;
1418 apx->error = mve_block_error_packed (enc, src, apx->block);
1423 mve_encode_0xe (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
1425 /* 1-color encoding: the whole block is 1 solid color (1 bytes) */
1426 guint8 median = mve_median (enc, src);
1428 memset (apx->block, median, 64);
1430 apx->data[0] = median;
1431 apx->error = mve_block_error_packed (enc, src, apx->block);
1436 mve_encode_0xf (GstMveEncoderData * enc, const guint8 * src, GstMveApprox * apx)
1438 /* 2 colors dithered encoding (2 bytes) */
1440 guint32 r[2] = { 0 }, g[2] = {
1445 /* find medians for both colors */
1446 for (y = 0; y < 8; ++y) {
1447 for (x = 0; x < 8; x += 2) {
1450 r[y & 1] += MVE_RVAL (p);
1451 g[y & 1] += MVE_GVAL (p);
1452 b[y & 1] += MVE_BVAL (p);
1455 r[(y & 1) ^ 1] += MVE_RVAL (p);
1456 g[(y & 1) ^ 1] += MVE_GVAL (p);
1457 b[(y & 1) ^ 1] += MVE_BVAL (p);
1459 src += enc->mve->width;
1461 col[0] = mve_find_pal_color (enc->palette,
1462 MVE_COL ((r[0] + 16) / 32, (g[0] + 16) / 32, (b[0] + 16) / 32));
1463 col[1] = mve_find_pal_color (enc->palette,
1464 MVE_COL ((r[1] + 16) / 32, (g[1] + 16) / 32, (b[1] + 16) / 32));
1466 /* store block after encoding */
1467 for (i = 0, y = 0; y < 8; ++y) {
1468 for (x = 0; x < 4; ++x) {
1469 apx->block[i++] = col[y & 1];
1470 apx->block[i++] = col[(y & 1) ^ 1];
1474 apx->data[0] = col[0];
1475 apx->data[1] = col[1];
1476 apx->error = mve_block_error_packed (enc,
1477 src - (8 * enc->mve->width), apx->block);
1481 /* all available encodings in the preferred order,
1482 i.e. in ascending encoded size */
1483 static const GstMveEncoding mve_encodings[] = {
1484 {0x1, 0, mve_encode_0x1},
1485 {0x0, 0, mve_encode_0x0},
1486 {0xe, 1, mve_encode_0xe},
1487 {0x3, 1, mve_encode_0x3},
1488 {0x4, 1, mve_encode_0x4},
1489 {0x2, 1, mve_encode_0x2},
1490 {0xf, 2, mve_encode_0xf},
1491 {0x5, 2, mve_encode_0x5},
1492 {0xd, 4, mve_encode_0xd},
1493 {0x7, 4, mve_encode_0x7a},
1494 {0x9, 8, mve_encode_0x9a},
1495 {0x7, 10, mve_encode_0x7b},
1496 {0x8, 12, mve_encode_0x8a},
1497 {0x8, 12, mve_encode_0x8b},
1498 {0x9, 12, mve_encode_0x9b},
1499 {0x9, 12, mve_encode_0x9c},
1500 {0xc, 16, mve_encode_0xc},
1501 {0x8, 16, mve_encode_0x8c},
1502 {0x9, 20, mve_encode_0x9d},
1503 {0xa, 24, mve_encode_0xaa},
1504 {0xa, 24, mve_encode_0xab},
1505 {0xa, 32, mve_encode_0xac},
1506 {0xb, 64, mve_encode_0xb}
1510 mve_reorder_solution (GArray ** solution, guint16 n)
1512 /* do a binary search to find the position to reinsert the modified element */
1513 /* the block we need to reconsider is always at position 0 */
1514 /* return TRUE if this block only has 1 encoding left and can be dropped */
1515 if (mve_comp_solution (&solution[0], &solution[1]) <= 0)
1516 return FALSE; /* already sorted */
1518 else if (solution[0]->len <= 1)
1519 /* drop this element from further calculations since we cannot improve here */
1523 /* we know the error value can only get worse, so we can actually start at 1 */
1525 guint upper = n - 1;
1529 while (upper > lower) {
1530 idx = lower + ((upper - lower) / 2);
1532 cmp = mve_comp_solution (&solution[0], &solution[idx]);
1536 } else if (cmp > 0) {
1539 upper = lower = idx;
1544 /* rearrange array members in new order */
1545 GArray *a = solution[0];
1547 memcpy (&solution[0], &solution[1], sizeof (GArray *) * idx);
1555 gst_mve_find_solution (GArray ** approx, guint16 n, guint32 size, guint16 max)
1557 /* build an array of approximations we can shuffle around */
1558 GstMveApprox *sol_apx;
1559 GArray **solution = g_malloc (sizeof (GArray *) * n);
1560 GArray **current = solution;
1562 memcpy (solution, approx, sizeof (GArray *) * n);
1564 qsort (solution, n, sizeof (GArray *), mve_comp_solution);
1567 /* array is now sorted by error of the next to optimal approximation;
1568 drop optimal approximation for the best block */
1570 /* unable to reduce size further */
1571 if (current[0]->len <= 1)
1574 sol_apx = &g_array_index (current[0], GstMveApprox, current[0]->len - 1);
1575 size -= mve_encodings[sol_apx->type].size;
1576 g_array_remove_index_fast (current[0], current[0]->len - 1);
1577 sol_apx = &g_array_index (current[0], GstMveApprox, current[0]->len - 1);
1578 size += mve_encodings[sol_apx->type].size;
1580 if (mve_reorder_solution (current, n)) {
1584 } while (size > max);
1592 mve_encode_frame8 (GstMveMux * mve, GstBuffer * frame, const guint32 * palette,
1596 GstFlowReturn ret = GST_FLOW_ERROR;
1597 guint8 *cm = mve->chunk_code_map;
1600 GstMveEncoderData enc;
1601 const guint16 blocks = (mve->width * mve->height) / 64;
1602 guint32 encoded_size = 0;
1605 src = GST_BUFFER_DATA (frame);
1607 approx = g_malloc (sizeof (GArray *) * blocks);
1610 enc.palette = palette;
1612 for (enc.y = 0; enc.y < mve->height; enc.y += 8) {
1613 for (enc.x = 0; enc.x < mve->width; enc.x += 8) {
1614 guint32 err, last_err = MVE_APPROX_MAX_ERROR;
1618 enc.q2available = enc.q4available = FALSE;
1619 approx[i] = g_array_new (FALSE, FALSE, sizeof (GstMveApprox));
1622 err = mve_encodings[type].approx (&enc, src, &apx);
1624 if (err < last_err) {
1625 apx.type = best = type;
1626 g_array_append_val (approx[i], apx);
1631 } while (last_err != 0);
1633 encoded_size += mve_encodings[best].size;
1637 src += 7 * mve->width;
1640 /* find best solution with size constraints */
1641 GST_DEBUG_OBJECT (mve, "encoded frame %u in %u bytes (lossless)",
1642 mve->video_frames + 1, encoded_size);
1646 src = GST_BUFFER_DATA (frame);
1647 for (i = 0, y = 0; y < mve->height; y += 8) {
1648 for (x = 0; x < mve->width; x += 8, ++i) {
1650 &g_array_index (approx[i], GstMveApprox, approx[i]->len - 1);
1651 guint opcode = mve_encodings[sol->type].opcode;
1655 GST_WARNING_OBJECT (mve, "error is %lu for %d/%d (0x%x)", sol->error, x,
1658 for (j = 0; j < 8; ++j) {
1659 guint8 *o = src + j * mve->width;
1660 guint8 *c = sol->block + j * 8;
1662 if (memcmp (o, c, 8)) {
1663 GST_WARNING_OBJECT (mve, "opcode 0x%x (type %d) at %d/%d, line %d:",
1664 opcode, sol->type, x, y, j + 1);
1665 for (k = 0; k < 8; ++k) {
1666 o = src + k * mve->width;
1667 c = sol->block + k * 8;
1668 GST_WARNING_OBJECT (mve,
1669 "%d should be: %4d %4d %4d %4d %4d %4d %4d %4d", k, o[0],
1670 o[1], o[2], o[3], o[4], o[5], o[6], o[7]);
1671 GST_WARNING_OBJECT (mve,
1672 "%d but is : %4d %4d %4d %4d %4d %4d %4d %4d", k, c[0],
1673 c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
1679 src += 7 * mve->width;
1683 if (encoded_size > max_data) {
1685 gst_mve_find_solution (approx, blocks, encoded_size, max_data);
1686 if (encoded_size > max_data) {
1687 GST_ERROR_OBJECT (mve, "unable to compress frame to less than %d bytes",
1689 for (i = 0; i < blocks; ++i)
1690 g_array_free (approx[i], TRUE);
1694 GST_DEBUG_OBJECT (mve, "compressed frame %u to %u bytes (lossy)",
1695 mve->video_frames + 1, encoded_size);
1698 mve->chunk_video = g_byte_array_sized_new (encoded_size);
1701 src = GST_BUFFER_DATA (frame);
1702 for (i = 0, y = 0; y < mve->height; y += 8) {
1703 for (x = 0; x < mve->width; x += 8, ++i) {
1705 &g_array_index (approx[i], GstMveApprox, approx[i]->len - 1);
1706 guint opcode = mve_encodings[sol->type].opcode;
1708 g_byte_array_append (mve->chunk_video, sol->data,
1709 mve_encodings[sol->type].size);
1717 /* modify the frame to match the image we actually encoded */
1719 mve_restore_block (mve, src, sol->block);
1722 g_array_free (approx[i], TRUE);
1724 src += 7 * mve->width;