summaryrefslogtreecommitdiff
path: root/gst/mve/mvevideoenc16.c
diff options
context:
space:
mode:
Diffstat (limited to 'gst/mve/mvevideoenc16.c')
-rw-r--r--gst/mve/mvevideoenc16.c1652
1 files changed, 0 insertions, 1652 deletions
diff --git a/gst/mve/mvevideoenc16.c b/gst/mve/mvevideoenc16.c
deleted file mode 100644
index 6afb33942..000000000
--- a/gst/mve/mvevideoenc16.c
+++ /dev/null
@@ -1,1652 +0,0 @@
-/*
- * Interplay MVE video encoder (16 bit)
- * Copyright (C) 2006 Jens Granseuer <jensgr@gmx.net>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include "gstmvemux.h"
-
-typedef struct _GstMveEncoderData GstMveEncoderData;
-typedef struct _GstMveEncoding GstMveEncoding;
-typedef struct _GstMveApprox GstMveApprox;
-typedef struct _GstMveQuant GstMveQuant;
-
-#define MVE_RMASK 0x7c00
-#define MVE_GMASK 0x03e0
-#define MVE_BMASK 0x001f
-#define MVE_RSHIFT 10
-#define MVE_GSHIFT 5
-#define MVE_BSHIFT 0
-
-#define MVE_RVAL(p) (((p) & MVE_RMASK) >> MVE_RSHIFT)
-#define MVE_GVAL(p) (((p) & MVE_GMASK) >> MVE_GSHIFT)
-#define MVE_BVAL(p) (((p) & MVE_BMASK) >> MVE_BSHIFT)
-#define MVE_COL(r,g,b) (((r) << MVE_RSHIFT) | ((g) << MVE_GSHIFT) | ((b) << MVE_BSHIFT))
-
-struct _GstMveEncoderData
-{
- GstMveMux *mve;
- /* current position in frame */
- guint16 x, y;
-
- /* commonly used quantization results
- (2 and 4 colors) for the current block */
- guint16 q2block[64];
- guint16 q2colors[2];
- guint32 q2error;
- gboolean q2available;
-
- guint16 q4block[64];
- guint16 q4colors[4];
- guint32 q4error;
- gboolean q4available;
-};
-
-struct _GstMveEncoding
-{
- guint8 opcode;
- guint8 size;
- guint32 (*approx) (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * res);
-};
-
-#define MVE_APPROX_MAX_ERROR G_MAXUINT32
-
-struct _GstMveApprox
-{
- guint32 error;
- guint8 type;
- guint8 data[128]; /* max 128 bytes encoded per block */
- guint16 block[64]; /* block in final image */
-};
-
-struct _GstMveQuant
-{
- guint16 col;
- guint16 r_total, g_total, b_total;
- guint8 r, g, b;
- guint8 hits, hits_last;
- guint32 max_error;
- guint16 max_miss;
-};
-
-#define mve_median(mve, src) mve_median_sub ((mve), (src), 8, 8, 0)
-#define mve_color_dist(c1, c2) \
- mve_color_dist_rgb (MVE_RVAL (c1), MVE_GVAL (c1), MVE_BVAL (c1), \
- MVE_RVAL (c2), MVE_GVAL (c2), MVE_BVAL (c2));
-
-/* comparison function for qsort() */
-static int
-mve_comp_solution (const void *a, const void *b)
-{
- const GArray *aa = *((GArray **) a);
- const GArray *bb = *((GArray **) b);
-
- if (aa->len <= 1)
- return G_MAXINT;
- else if (bb->len <= 1)
- return G_MININT;
- else
- return g_array_index (aa, GstMveApprox, aa->len - 2).error -
- g_array_index (bb, GstMveApprox, bb->len - 2).error;
-}
-
-static inline guint32
-mve_color_dist_rgb (guint8 r1, guint8 g1, guint8 b1,
- guint8 r2, guint8 g2, guint8 b2)
-{
- /* euclidean distance (minus sqrt) */
- gint dr = r1 - r2;
- gint dg = g1 - g2;
- gint db = b1 - b2;
-
- return dr * dr + dg * dg + db * db;
-}
-
-/* compute average color in a sub-block */
-static guint16
-mve_median_sub (const GstMveMux * mve, const guint16 * src, guint w, guint h,
- guint n)
-{
- guint x, y;
- const guint max = w * h, max2 = max >> 1;
- guint32 r_total = max2, g_total = max2, b_total = max2;
-
- src += ((n * w) % 8) + (((n * (8 - h)) / (12 - w)) * h * mve->width);
-
- for (y = 0; y < h; ++y) {
- for (x = 0; x < w; ++x) {
- r_total += MVE_RVAL (src[x]);
- g_total += MVE_GVAL (src[x]);
- b_total += MVE_BVAL (src[x]);
- }
- src += mve->width;
- }
-
- return MVE_COL (r_total / max, g_total / max, b_total / max);
-}
-
-static void
-mve_quant_init (const GstMveMux * mve, GstMveQuant * q, guint n_clusters,
- const guint16 * data, guint w, guint h)
-{
- guint i;
- guint x, y;
- guint16 cols[4];
- guint16 val[2];
-
- /* init first cluster with lowest (darkest), second with highest (lightest)
- color. if we need 4 clusters, fill in first and last color in the block
- and hope they make for a good distribution */
- cols[0] = cols[1] = cols[2] = data[0];
- cols[3] = data[(h - 1) * mve->width + w - 1];
-
- /* favour red over green and blue */
- val[0] = val[1] =
- (MVE_RVAL (data[0]) << 1) + MVE_GVAL (data[0]) + MVE_BVAL (data[0]);
-
- for (y = 0; y < h; ++y) {
- for (x = 0; x < w; ++x) {
- guint16 c = data[x];
-
- if ((c != cols[0]) && (c != cols[1])) {
- guint v = (MVE_RVAL (c) << 1) + MVE_GVAL (c) + MVE_BVAL (c);
-
- if (v < val[0]) {
- val[0] = v;
- cols[0] = c;
- } else if (v > val[1]) {
- val[1] = v;
- cols[1] = c;
- }
- }
- }
- data += mve->width;
- }
-
- for (i = 0; i < n_clusters; ++i) {
- q[i].col = cols[i];
- q[i].r = MVE_RVAL (cols[i]);
- q[i].g = MVE_GVAL (cols[i]);
- q[i].b = MVE_BVAL (cols[i]);
- q[i].r_total = q[i].g_total = q[i].b_total = 0;
- q[i].hits = q[i].hits_last = 0;
- q[i].max_error = 0;
- q[i].max_miss = 0;
- }
-}
-
-static gboolean
-mve_quant_update_clusters (GstMveQuant * q, guint n_clusters)
-{
- gboolean changed = FALSE;
- guint i;
-
- for (i = 0; i < n_clusters; ++i) {
- if (q[i].hits > 0) {
- guint16 means = MVE_COL ((q[i].r_total + q[i].hits / 2) / q[i].hits,
- (q[i].g_total + q[i].hits / 2) / q[i].hits,
- (q[i].b_total + q[i].hits / 2) / q[i].hits);
-
- if ((means != q[i].col) || (q[i].hits != q[i].hits_last))
- changed = TRUE;
-
- q[i].col = means;
- q[i].r_total = q[i].g_total = q[i].b_total = 0;
- } else {
- guint j;
- guint32 max_err = 0;
- GstMveQuant *worst = NULL;
-
- /* try to replace unused cluster with a better representative */
- for (j = 0; j < n_clusters; ++j) {
- if (q[j].max_error > max_err) {
- worst = &q[j];
- max_err = worst->max_error;
- }
- }
- if (worst) {
- q[i].col = worst->max_miss;
- worst->max_error = 0;
- changed = TRUE;
- }
- }
-
- q[i].r = MVE_RVAL (q[i].col);
- q[i].g = MVE_GVAL (q[i].col);
- q[i].b = MVE_BVAL (q[i].col);
- q[i].hits_last = q[i].hits;
- q[i].hits = 0;
- }
- for (i = 0; i < n_clusters; ++i) {
- q[i].max_error = 0;
- }
-
- return changed;
-}
-
-/* quantize a sub-block using a k-means algorithm */
-static guint32
-mve_quantize (const GstMveMux * mve, const guint16 * src,
- guint w, guint h, guint n, guint ncols, guint16 * scratch, guint16 * cols)
-{
- guint x, y, i;
- GstMveQuant q[4];
- const guint16 *data;
- guint16 *dest;
- guint32 error;
-
- g_assert (n <= 4 && ncols <= 4);
-
- src += ((n * w) % 8) + (((n * (8 - h)) / (12 - w)) * h * mve->width);
- scratch += ((n * w) % 8) + (((n * (8 - h)) / (12 - w)) * h * 8);
-
- mve_quant_init (mve, q, ncols, src, w, h);
-
- do {
- data = src;
- dest = scratch;
- error = 0;
-
- /* for each pixel find the closest cluster */
- for (y = 0; y < h; ++y) {
- for (x = 0; x < w; ++x) {
- guint16 c = data[x];
- guint8 r = MVE_RVAL (c), g = MVE_GVAL (c), b = MVE_BVAL (c);
- guint32 minerr = MVE_APPROX_MAX_ERROR, err;
- GstMveQuant *best = NULL;
-
- for (i = 0; i < ncols; ++i) {
- err = mve_color_dist_rgb (r, g, b, q[i].r, q[i].g, q[i].b);
-
- if (err < minerr) {
- minerr = err;
- best = &q[i];
- }
- }
-
- if (G_UNLIKELY (!best))
- continue;
-
- ++best->hits;
- best->r_total += r;
- best->g_total += g;
- best->b_total += b;
-
- if (minerr > best->max_error) {
- best->max_error = minerr;
- best->max_miss = c;
- }
-
- error += minerr;
- dest[x] = best->col;
- }
- data += mve->width;
- dest += 8;
- }
- } while (mve_quant_update_clusters (q, ncols));
-
- /* fill cols array with result colors */
- for (i = 0; i < ncols; ++i)
- cols[i] = q[i].col;
-
- return error;
-}
-
-static guint32
-mve_block_error (const GstMveMux * mve, const guint16 * b1, const guint16 * b2,
- guint32 threshold)
-{
- /* compute error between two blocks in a frame */
- guint32 e = 0;
- guint x, y;
-
- for (y = 0; y < 8; ++y) {
- for (x = 0; x < 8; ++x) {
- e += mve_color_dist (*b1, *b2);
-
- /* using a threshold to return early gives a huge performance bonus */
- if (e >= threshold)
- return MVE_APPROX_MAX_ERROR;
- ++b1;
- ++b2;
- }
-
- b1 += mve->width - 8;
- b2 += mve->width - 8;
- }
-
- return e;
-}
-
-static guint32
-mve_block_error_packed (const GstMveMux * mve, const guint16 * block,
- const guint16 * scratch)
-{
- /* compute error between a block in a frame and a (continuous) scratch pad */
- guint32 e = 0;
- guint x, y;
-
- for (y = 0; y < 8; ++y) {
- for (x = 0; x < 8; ++x) {
- e += mve_color_dist (block[x], scratch[x]);
- }
- block += mve->width;
- scratch += 8;
- }
-
- return e;
-}
-
-static void
-mve_store_block (const GstMveMux * mve, const guint16 * block,
- guint16 * scratch)
-{
- /* copy block from frame to a (continuous) scratch pad */
- guint y;
-
- for (y = 0; y < 8; ++y) {
- memcpy (scratch, block, 16);
- block += mve->width;
- scratch += 8;
- }
-}
-
-static void
-mve_restore_block (const GstMveMux * mve, guint16 * block,
- const guint16 * scratch)
-{
- /* copy block from scratch pad to frame */
- guint y;
-
- for (y = 0; y < 8; ++y) {
- memcpy (block, scratch, 16);
- block += mve->width;
- scratch += 8;
- }
-}
-
-
-static guint32
-mve_try_vector (GstMveEncoderData * enc, const guint16 * src,
- const guint16 * frame, gint pn, GstMveApprox * apx)
-{
- /* try to locate a similar 8x8 block in the given frame using a motion vector */
- guint i;
- gint dx, dy;
- gint fx, fy;
- guint32 err;
-
- apx->error = MVE_APPROX_MAX_ERROR;
-
- for (i = 0; i < 256; ++i) {
- if (i < 56) {
- dx = 8 + (i % 7);
- dy = i / 7;
- } else {
- dx = -14 + ((i - 56) % 29);
- dy = 8 + ((i - 56) / 29);
- }
-
- fx = enc->x + dx * pn;
- fy = enc->y + dy * pn;
-
- if ((fx >= 0) && (fy >= 0) && (fx + 8 <= enc->mve->width)
- && (fy + 8 <= enc->mve->height)) {
- err =
- mve_block_error (enc->mve, src, frame + fy * enc->mve->width + fx,
- apx->error);
- if (err < apx->error) {
- apx->data[0] = i;
- mve_store_block (enc->mve, frame + fy * enc->mve->width + fx,
- apx->block);
- apx->error = err;
- if (err == 0)
- return 0;
- }
- }
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0x0 (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* copy a block from the last frame (0 bytes) */
- if (enc->mve->last_frame == NULL)
- return MVE_APPROX_MAX_ERROR;
-
- mve_store_block (enc->mve,
- ((guint16 *) GST_BUFFER_DATA (enc->mve->last_frame)) +
- enc->y * enc->mve->width + enc->x, apx->block);
- apx->error = mve_block_error_packed (enc->mve, src, apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x1 (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* copy a block from the second to last frame (0 bytes) */
- if (enc->mve->second_last_frame == NULL)
- return MVE_APPROX_MAX_ERROR;
-
- mve_store_block (enc->mve,
- ((guint16 *) GST_BUFFER_DATA (enc->mve->second_last_frame)) +
- enc->y * enc->mve->width + enc->x, apx->block);
- apx->error = mve_block_error_packed (enc->mve, src, apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x2 (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* copy block from 2 frames ago using a motion vector (1 byte) */
- if (enc->mve->quick_encoding || enc->mve->second_last_frame == NULL)
- return MVE_APPROX_MAX_ERROR;
-
- apx->error = mve_try_vector (enc, src,
- (guint16 *) GST_BUFFER_DATA (enc->mve->second_last_frame), 1, apx);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x3 (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* copy 8x8 block from current frame from an up/left block (1 byte) */
- if (enc->mve->quick_encoding)
- return MVE_APPROX_MAX_ERROR;
-
- apx->error = mve_try_vector (enc, src,
- src - enc->mve->width * enc->y - enc->x, -1, apx);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x4 (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* copy a block from previous frame using a motion vector (-8/-8 to +7/+7) (1 byte) */
- const GstMveMux *mve = enc->mve;
- guint32 err;
- const guint16 *frame;
- gint x1, x2, xi, y1, y2, yi;
-
- if (mve->last_frame == NULL)
- return MVE_APPROX_MAX_ERROR;
-
- frame = (guint16 *) GST_BUFFER_DATA (mve->last_frame);
-
- x1 = enc->x - 8;
- x2 = enc->x + 7;
- if (x1 < 0)
- x1 = 0;
- else if (x2 + 8 > mve->width)
- x2 = mve->width - 8;
-
- y1 = enc->y - 8;
- y2 = enc->y + 7;
- if (y1 < 0)
- y1 = 0;
- else if (y2 + 8 > mve->height)
- y2 = mve->height - 8;
-
- apx->error = MVE_APPROX_MAX_ERROR;
-
- for (yi = y1; yi <= y2; ++yi) {
- guint yoff = yi * mve->width;
-
- for (xi = x1; xi <= x2; ++xi) {
- err = mve_block_error (mve, src, frame + yoff + xi, apx->error);
- if (err < apx->error) {
- apx->data[0] = ((xi - enc->x + 8) & 0xF) | ((yi - enc->y + 8) << 4);
- mve_store_block (mve, frame + yoff + xi, apx->block);
- apx->error = err;
- if (err == 0)
- return 0;
- }
- }
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0x5 (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* copy a block from previous frame using a motion vector
- (-128/-128 to +127/+127) (2 bytes) */
- const GstMveMux *mve = enc->mve;
- guint32 err;
- const guint16 *frame;
- gint x1, x2, xi, y1, y2, yi;
-
- if (mve->quick_encoding || mve->last_frame == NULL)
- return MVE_APPROX_MAX_ERROR;
-
- frame = (guint16 *) GST_BUFFER_DATA (mve->last_frame);
-
- x1 = enc->x - 128;
- x2 = enc->x + 127;
- if (x1 < 0)
- x1 = 0;
- if (x2 + 8 > mve->width)
- x2 = mve->width - 8;
-
- y1 = enc->y - 128;
- y2 = enc->y + 127;
- if (y1 < 0)
- y1 = 0;
- if (y2 + 8 > mve->height)
- y2 = mve->height - 8;
-
- apx->error = MVE_APPROX_MAX_ERROR;
-
- for (yi = y1; yi <= y2; ++yi) {
- gint yoff = yi * mve->width;
-
- for (xi = x1; xi <= x2; ++xi) {
- err = mve_block_error (mve, src, frame + yoff + xi, apx->error);
- if (err < apx->error) {
- apx->data[0] = xi - enc->x;
- apx->data[1] = yi - enc->y;
- mve_store_block (mve, frame + yoff + xi, apx->block);
- apx->error = err;
- if (err == 0)
- return 0;
- }
- }
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0x7a (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 2-color encoding for 2x2 solid blocks (6 bytes) */
- guint16 p[2];
- guint16 mean;
- guint32 e1, e2;
- guint x, y;
- guint8 r[2], g[2], b[2], rb, gb, bb;
- guint16 *block = apx->block;
- guint16 mask = 0x0001;
- guint16 flags = 0;
-
- /* calculate mean colors for the entire block */
- if (!enc->q2available) {
- enc->q2error =
- mve_quantize (enc->mve, src, 8, 8, 0, 2, enc->q2block, enc->q2colors);
- enc->q2available = TRUE;
- }
-
- /* p[0] & 0x8000 */
- GST_WRITE_UINT16_LE (&apx->data[0], enc->q2colors[0] | 0x8000);
- GST_WRITE_UINT16_LE (&apx->data[2], enc->q2colors[1]);
-
- for (x = 0; x < 2; ++x) {
- r[x] = MVE_RVAL (enc->q2colors[x]);
- g[x] = MVE_GVAL (enc->q2colors[x]);
- b[x] = MVE_BVAL (enc->q2colors[x]);
- }
-
- /* calculate mean colors for each 2x2 block and map to global colors */
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 4; ++x, mask <<= 1) {
- p[0] = src[enc->mve->width];
- p[1] = src[enc->mve->width + 1];
-
- rb = (MVE_RVAL (src[0]) + MVE_RVAL (src[1]) + MVE_RVAL (p[0]) +
- MVE_RVAL (p[1]) + 2) / 4;
- gb = (MVE_GVAL (src[0]) + MVE_GVAL (src[1]) + MVE_GVAL (p[0]) +
- MVE_GVAL (p[1]) + 2) / 4;
- bb = (MVE_BVAL (src[0]) + MVE_BVAL (src[1]) + MVE_BVAL (p[0]) +
- MVE_BVAL (p[1]) + 2) / 4;
-
- e1 = mve_color_dist_rgb (rb, gb, bb, r[0], g[0], b[0]);
- e2 = mve_color_dist_rgb (rb, gb, bb, r[1], g[1], b[1]);
-
- if (e1 > e2) {
- mean = enc->q2colors[1];
- flags |= mask;
- } else {
- mean = enc->q2colors[0];
- }
-
- block[0] = block[1] = block[8] = block[9] = mean;
-
- src += 2;
- block += 2;
- }
- src += (enc->mve->width * 2) - 8;
- block += 8;
- }
-
- apx->data[4] = flags & 0x00FF;
- apx->data[5] = (flags & 0xFF00) >> 8;
-
- apx->error =
- mve_block_error_packed (enc->mve, src - enc->mve->width * 8, apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x7b (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* generic 2-color encoding (12 bytes) */
- guint x, y;
- guint8 *data = apx->data;
- guint16 *block = apx->block;
-
- if (!enc->q2available) {
- enc->q2error =
- mve_quantize (enc->mve, src, 8, 8, 0, 2, enc->q2block, enc->q2colors);
- enc->q2available = TRUE;
- }
-
- memcpy (block, enc->q2block, 128);
-
- /* !(p[0] & 0x8000) */
- GST_WRITE_UINT16_LE (&data[0], enc->q2colors[0] & ~0x8000);
- GST_WRITE_UINT16_LE (&data[2], enc->q2colors[1]);
- data += 4;
-
- for (y = 0; y < 8; ++y) {
- guint8 flags = 0;
-
- for (x = 0x01; x <= 0x80; x <<= 1) {
- if (*block == enc->q2colors[1])
- flags |= x;
- ++block;
- }
- *data++ = flags;
- }
-
- apx->error = enc->q2error;
- return apx->error;
-}
-
-static guint32
-mve_encode_0x8a (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 2-color encoding for top and bottom half (16 bytes) */
- guint16 cols[2];
- guint32 flags;
- guint i, x, y, shifter;
- guint16 *block = apx->block;
- guint8 *data = apx->data;
-
- apx->error = 0;
-
- for (i = 0; i < 2; ++i) {
- apx->error += mve_quantize (enc->mve, src, 8, 4, i, 2, apx->block, cols);
-
- flags = 0;
- shifter = 0;
-
- /* p0 & 0x8000 && p2 & 0x8000 */
- GST_WRITE_UINT16_LE (&data[0], cols[0] | 0x8000);
- GST_WRITE_UINT16_LE (&data[2], cols[1]);
-
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 8; ++x, ++shifter) {
- if (block[x] == cols[1])
- flags |= 1 << shifter;
- }
- block += 8;
- }
- data[4] = flags & 0x000000FF;
- data[5] = (flags & 0x0000FF00) >> 8;
- data[6] = (flags & 0x00FF0000) >> 16;
- data[7] = (flags & 0xFF000000) >> 24;
- data += 8;
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0x8b (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 2-color encoding for left and right half (16 bytes) */
- guint16 cols[2];
- guint32 flags;
- guint i, x, y, shifter;
- guint16 *block = apx->block;
- guint8 *data = apx->data;
-
- apx->error = 0;
-
- for (i = 0; i < 2; ++i) {
- apx->error += mve_quantize (enc->mve, src, 4, 8, i, 2, apx->block, cols);
-
- flags = 0;
- shifter = 0;
-
- /* p0 & 0x8000 && !(p2 & 0x8000) */
- GST_WRITE_UINT16_LE (&data[0], (cols[0] & ~0x8000) | (0x8000 * (i ^ 1)));
- GST_WRITE_UINT16_LE (&data[2], cols[1]);
-
- for (y = 0; y < 8; ++y) {
- for (x = 0; x < 4; ++x, ++shifter) {
- if (block[x] == cols[1])
- flags |= 1 << shifter;
- }
- block += 8;
- }
-
- data[4] = flags & 0x000000FF;
- data[5] = (flags & 0x0000FF00) >> 8;
- data[6] = (flags & 0x00FF0000) >> 16;
- data[7] = (flags & 0xFF000000) >> 24;
- data += 8;
- block = apx->block + 4;
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0x8c (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 2-color encoding for each 4x4 quadrant (24 bytes) */
- guint16 cols[2];
- guint16 flags;
- guint i, x, y, shifter;
- guint16 *block;
- guint8 *data = apx->data;
-
- apx->error = 0;
-
- for (i = 0; i < 4; ++i) {
- apx->error +=
- mve_quantize (enc->mve, src, 4, 4, ((i & 1) << 1) | ((i & 2) >> 1), 2,
- apx->block, cols);
-
- /* !(p0 & 0x8000) */
- GST_WRITE_UINT16_LE (&data[0], cols[0] & ~0x8000);
- GST_WRITE_UINT16_LE (&data[2], cols[1]);
-
- block = apx->block + ((i / 2) * 4) + ((i % 2) * 32);
- flags = 0;
- shifter = 0;
-
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 4; ++x, ++shifter) {
- if (block[x] == cols[1])
- flags |= 1 << shifter;
- }
- block += 8;
- }
-
- data[4] = flags & 0x00FF;
- data[5] = (flags & 0xFF00) >> 8;
- data += 6;
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0x9a (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 4-color encoding for 2x2 solid blocks (12 bytes) */
- guint16 p[2];
- guint32 e, emin;
- guint i, x, y, mean = 0;
- guint8 r[4], g[4], b[4], rb, gb, bb;
- guint16 *block = apx->block;
- guint shifter = 0;
- guint32 flags = 0;
-
- /* calculate mean colors for the entire block */
- if (!enc->q4available) {
- enc->q4error =
- mve_quantize (enc->mve, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
- enc->q4available = TRUE;
- }
-
- /* !(p[0] & 0x8000) && p[2] & 0x8000 */
- GST_WRITE_UINT16_LE (&apx->data[0], enc->q4colors[0] & ~0x8000);
- GST_WRITE_UINT16_LE (&apx->data[2], enc->q4colors[1]);
- GST_WRITE_UINT16_LE (&apx->data[4], enc->q4colors[2] | 0x8000);
- GST_WRITE_UINT16_LE (&apx->data[6], enc->q4colors[3]);
-
- for (i = 0; i < 4; ++i) {
- r[i] = MVE_RVAL (enc->q4colors[i]);
- g[i] = MVE_GVAL (enc->q4colors[i]);
- b[i] = MVE_BVAL (enc->q4colors[i]);
- }
-
- /* calculate mean colors for each 2x2 block and map to global colors */
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 4; ++x, shifter += 2) {
- p[0] = src[enc->mve->width];
- p[1] = src[enc->mve->width + 1];
-
- rb = (MVE_RVAL (src[0]) + MVE_RVAL (src[1]) + MVE_RVAL (p[0]) +
- MVE_RVAL (p[1]) + 2) / 4;
- gb = (MVE_GVAL (src[0]) + MVE_GVAL (src[1]) + MVE_GVAL (p[0]) +
- MVE_GVAL (p[1]) + 2) / 4;
- bb = (MVE_BVAL (src[0]) + MVE_BVAL (src[1]) + MVE_BVAL (p[0]) +
- MVE_BVAL (p[1]) + 2) / 4;
-
- emin = MVE_APPROX_MAX_ERROR;
- for (i = 0; i < 4; ++i) {
- e = mve_color_dist_rgb (rb, gb, bb, r[i], g[i], b[i]);
- if (e < emin) {
- emin = e;
- mean = i;
- }
- }
-
- flags |= mean << shifter;
- block[0] = block[1] = block[8] = block[9] = enc->q4colors[mean];
-
- src += 2;
- block += 2;
- }
- src += (enc->mve->width * 2) - 8;
- block += 8;
- }
-
- apx->data[8] = flags & 0x000000FF;
- apx->data[9] = (flags & 0x0000FF00) >> 8;
- apx->data[10] = (flags & 0x00FF0000) >> 16;
- apx->data[11] = (flags & 0xFF000000) >> 24;
-
- apx->error =
- mve_block_error_packed (enc->mve, src - 8 * enc->mve->width, apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x9b (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 4-color encoding for 2x1 solid blocks (16 bytes) */
- guint32 e, emin;
- guint i, x, y, mean = 0;
- guint8 r[4], g[4], b[4], rb, gb, bb;
- guint8 *data = apx->data;
- guint16 *block = apx->block;
- guint shifter = 0;
- guint32 flags = 0;
-
- /* calculate mean colors for the entire block */
- if (!enc->q4available) {
- enc->q4error =
- mve_quantize (enc->mve, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
- enc->q4available = TRUE;
- }
-
- /* p[0] & 0x8000 && !(p[2] & 0x8000) */
- GST_WRITE_UINT16_LE (&data[0], enc->q4colors[0] | 0x8000);
- GST_WRITE_UINT16_LE (&data[2], enc->q4colors[1]);
- GST_WRITE_UINT16_LE (&data[4], enc->q4colors[2] & ~0x8000);
- GST_WRITE_UINT16_LE (&data[6], enc->q4colors[3]);
- data += 8;
-
- for (i = 0; i < 4; ++i) {
- r[i] = MVE_RVAL (enc->q4colors[i]);
- g[i] = MVE_GVAL (enc->q4colors[i]);
- b[i] = MVE_BVAL (enc->q4colors[i]);
- }
-
- /* calculate mean colors for each 2x1 block and map to global colors */
- for (y = 0; y < 8; ++y) {
- for (x = 0; x < 4; ++x, shifter += 2) {
- rb = (MVE_RVAL (src[0]) + MVE_RVAL (src[1]) + 1) / 2;
- gb = (MVE_GVAL (src[0]) + MVE_GVAL (src[1]) + 1) / 2;
- bb = (MVE_BVAL (src[0]) + MVE_BVAL (src[1]) + 1) / 2;
-
- emin = MVE_APPROX_MAX_ERROR;
- for (i = 0; i < 4; ++i) {
- e = mve_color_dist_rgb (rb, gb, bb, r[i], g[i], b[i]);
- if (e < emin) {
- emin = e;
- mean = i;
- }
- }
-
- flags |= mean << shifter;
- block[0] = block[1] = enc->q4colors[mean];
-
- src += 2;
- block += 2;
- }
-
- if ((y == 3) || (y == 7)) {
- data[0] = flags & 0x000000FF;
- data[1] = (flags & 0x0000FF00) >> 8;
- data[2] = (flags & 0x00FF0000) >> 16;
- data[3] = (flags & 0xFF000000) >> 24;
- data += 4;
-
- flags = 0;
- shifter = 0;
- }
-
- src += enc->mve->width - 8;
- }
-
- apx->error =
- mve_block_error_packed (enc->mve, src - 8 * enc->mve->width, apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x9c (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 4-color encoding for 1x2 solid blocks (16 bytes) */
- guint16 p2;
- guint32 e, emin;
- guint i, x, y, mean = 0;
- guint8 r[4], g[4], b[4], rb, gb, bb;
- guint8 *data = apx->data;
- guint16 *block = apx->block;
- guint shifter = 0;
- guint32 flags = 0;
-
- /* calculate mean colors for the entire block */
- if (!enc->q4available) {
- enc->q4error =
- mve_quantize (enc->mve, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
- enc->q4available = TRUE;
- }
-
- /* p[0] & 0x8000 && p[2] & 0x8000 */
- GST_WRITE_UINT16_LE (&data[0], enc->q4colors[0] | 0x8000);
- GST_WRITE_UINT16_LE (&data[2], enc->q4colors[1]);
- GST_WRITE_UINT16_LE (&data[4], enc->q4colors[2] | 0x8000);
- GST_WRITE_UINT16_LE (&data[6], enc->q4colors[3]);
- data += 8;
-
- for (i = 0; i < 4; ++i) {
- r[i] = MVE_RVAL (enc->q4colors[i]);
- g[i] = MVE_GVAL (enc->q4colors[i]);
- b[i] = MVE_BVAL (enc->q4colors[i]);
- }
-
- /* calculate mean colors for each 1x2 block and map to global colors */
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 8; ++x, shifter += 2) {
- p2 = src[enc->mve->width];
- rb = (MVE_RVAL (src[0]) + MVE_RVAL (p2) + 1) / 2;
- gb = (MVE_GVAL (src[0]) + MVE_GVAL (p2) + 1) / 2;
- bb = (MVE_BVAL (src[0]) + MVE_BVAL (p2) + 1) / 2;
-
- emin = MVE_APPROX_MAX_ERROR;
- for (i = 0; i < 4; ++i) {
- e = mve_color_dist_rgb (rb, gb, bb, r[i], g[i], b[i]);
- if (e < emin) {
- emin = e;
- mean = i;
- }
- }
-
- flags |= mean << shifter;
- block[0] = block[8] = enc->q4colors[mean];
-
- ++src;
- ++block;
- }
-
- if ((y == 1) || (y == 3)) {
- data[0] = flags & 0x000000FF;
- data[1] = (flags & 0x0000FF00) >> 8;
- data[2] = (flags & 0x00FF0000) >> 16;
- data[3] = (flags & 0xFF000000) >> 24;
- data += 4;
-
- flags = 0;
- shifter = 0;
- }
-
- src += (enc->mve->width * 2) - 8;
- block += 8;
- }
-
- apx->error =
- mve_block_error_packed (enc->mve, src - 8 * enc->mve->width, apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0x9d (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* generic 4-color encoding (24 bytes) */
- guint32 flags = 0;
- guint shifter = 0;
- guint i, x, y;
- guint8 *data = apx->data;
- guint16 *block = apx->block;
-
- if (!enc->q4available) {
- enc->q4error =
- mve_quantize (enc->mve, src, 8, 8, 0, 4, enc->q4block, enc->q4colors);
- enc->q4available = TRUE;
- }
-
- memcpy (block, enc->q4block, 128);
-
- /* !(p[0] & 0x8000) && !(p[2] & 0x8000) */
- GST_WRITE_UINT16_LE (&data[0], enc->q4colors[0] & ~0x8000);
- GST_WRITE_UINT16_LE (&data[2], enc->q4colors[1]);
- GST_WRITE_UINT16_LE (&data[4], enc->q4colors[2] & ~0x8000);
- GST_WRITE_UINT16_LE (&data[6], enc->q4colors[3]);
- data += 8;
-
- for (y = 0; y < 8; ++y) {
- for (x = 0; x < 8; ++x, shifter += 2) {
-
- for (i = 0; i < 3; ++i) {
- if (*block == enc->q4colors[i])
- break;
- }
-
- flags |= i << shifter;
- ++block;
- }
-
- data[0] = flags & 0x000000FF;
- data[1] = (flags & 0x0000FF00) >> 8;
- data += 2;
- shifter = 0;
- flags = 0;
- }
-
- apx->error = enc->q4error;
- return apx->error;
-}
-
-static guint32
-mve_encode_0xaa (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 4-color encoding for top and bottom half (32 bytes) */
- guint16 cols[4];
- guint32 flags;
- guint i, j, x, y, shifter;
- guint16 *block = apx->block;
- guint8 *data = apx->data;
-
- apx->error = 0;
-
- for (i = 0; i < 2; ++i) {
- apx->error += mve_quantize (enc->mve, src, 8, 4, i, 4, apx->block, cols);
-
- flags = 0;
- shifter = 0;
-
- /* p0 & 0x8000 && p4 & 0x8000 */
- GST_WRITE_UINT16_LE (&data[0], cols[0] | 0x8000);
- GST_WRITE_UINT16_LE (&data[2], cols[1]);
- GST_WRITE_UINT16_LE (&data[4], cols[2]);
- GST_WRITE_UINT16_LE (&data[6], cols[3]);
- data += 8;
-
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 8; ++x, shifter += 2) {
- for (j = 0; j < 3; ++j) {
- if (block[x] == cols[j])
- break;
- }
- flags |= j << shifter;
- }
- block += 8;
-
- if ((y == 1) || (y == 3)) {
- data[0] = flags & 0x000000FF;
- data[1] = (flags & 0x0000FF00) >> 8;
- data[2] = (flags & 0x00FF0000) >> 16;
- data[3] = (flags & 0xFF000000) >> 24;
- data += 4;
- flags = 0;
- shifter = 0;
- }
- }
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0xab (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 4-color encoding for left and right half (32 bytes) */
- guint16 cols[4];
- guint32 flags;
- guint i, j, x, y, shifter;
- guint16 *block = apx->block;
- guint8 *data = apx->data;
-
- apx->error = 0;
-
- for (i = 0; i < 2; ++i) {
- apx->error += mve_quantize (enc->mve, src, 4, 8, i, 4, apx->block, cols);
-
- flags = 0;
- shifter = 0;
-
- /* p0 & 0x8000 && !(p4 & 0x8000) */
- GST_WRITE_UINT16_LE (&data[0], (cols[0] & ~0x8000) | (0x8000 * (i ^ 1)));
- GST_WRITE_UINT16_LE (&data[2], cols[1]);
- GST_WRITE_UINT16_LE (&data[4], cols[2]);
- GST_WRITE_UINT16_LE (&data[6], cols[3]);
- data += 8;
-
- for (y = 0; y < 8; ++y) {
- for (x = 0; x < 4; ++x, shifter += 2) {
- for (j = 0; j < 3; ++j) {
- if (block[x] == cols[j])
- break;
- }
- flags |= j << shifter;
- }
- block += 8;
-
- if ((y == 3) || (y == 7)) {
- data[0] = flags & 0x000000FF;
- data[1] = (flags & 0x0000FF00) >> 8;
- data[2] = (flags & 0x00FF0000) >> 16;
- data[3] = (flags & 0xFF000000) >> 24;
- data += 4;
- flags = 0;
- shifter = 0;
- }
- }
- block = apx->block + 4;
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0xac (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 4-color encoding for each 4x4 quadrant (48 bytes) */
- guint16 cols[4];
- guint32 flags;
- guint i, j, x, y, shifter;
- guint16 *block;
- guint8 *data = apx->data;
-
- apx->error = 0;
-
- for (i = 0; i < 4; ++i) {
- apx->error +=
- mve_quantize (enc->mve, src, 4, 4, ((i & 1) << 1) | ((i & 2) >> 1), 4,
- apx->block, cols);
-
- /* !(p0 & 0x8000) */
- GST_WRITE_UINT16_LE (&data[0], cols[0] & ~0x8000);
- GST_WRITE_UINT16_LE (&data[2], cols[1]);
- GST_WRITE_UINT16_LE (&data[4], cols[2]);
- GST_WRITE_UINT16_LE (&data[6], cols[3]);
-
- block = apx->block + ((i / 2) * 4) + ((i % 2) * 32);
- flags = 0;
- shifter = 0;
-
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 4; ++x, shifter += 2) {
- for (j = 0; j < 3; ++j) {
- if (block[x] == cols[j])
- break;
- }
- flags |= j << shifter;
- }
- block += 8;
- }
-
- data[8] = flags & 0x000000FF;
- data[9] = (flags & 0x0000FF00) >> 8;
- data[10] = (flags & 0x00FF0000) >> 16;
- data[11] = (flags & 0xFF000000) >> 24;
- data += 12;
- }
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0xb (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 64-color encoding (each pixel in block is a different color) (128 bytes) */
- guint i;
-
- apx->error = 0;
-
- mve_store_block (enc->mve, src, apx->block);
- for (i = 0; i < 64; ++i)
- GST_WRITE_UINT16_LE (&apx->data[i << 1], apx->block[i]);
-
- return 0;
-}
-
-static guint32
-mve_encode_0xc (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 16-color block encoding: each 2x2 block is a different color (32 bytes) */
- guint i = 0, x, y;
- const guint w = enc->mve->width;
- guint16 r, g, b;
-
- /* calculate median color for each 2x2 block */
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 4; ++x) {
- r = MVE_RVAL (src[0]) + MVE_RVAL (src[1]) +
- MVE_RVAL (src[w]) + MVE_RVAL (src[w + 1]) + 2;
- g = MVE_GVAL (src[0]) + MVE_GVAL (src[1]) +
- MVE_GVAL (src[w]) + MVE_GVAL (src[w + 1]) + 2;
- b = MVE_BVAL (src[0]) + MVE_BVAL (src[1]) +
- MVE_BVAL (src[w]) + MVE_BVAL (src[w + 1]) + 2;
- apx->block[i] = apx->block[i + 1] = apx->block[i + 2] =
- apx->block[i + 3] = MVE_COL (r >> 2, g >> 2, b >> 2);
- GST_WRITE_UINT16_LE (&apx->data[i >> 1], apx->block[i]);
-
- i += 4;
- src += 2;
- }
- src += (w * 2) - 8;
- }
-
- apx->error = mve_block_error_packed (enc->mve, src - (8 * w), apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0xd (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 4-color block encoding: each 4x4 block is a different color (8 bytes) */
- guint i, x, y;
- guint16 *block;
-
- /* calculate median color for each 4x4 block */
- for (i = 0; i < 4; ++i) {
- guint16 median =
- mve_median_sub (enc->mve, src, 4, 4, ((i & 1) << 1) | ((i & 2) >> 1));
-
- block = apx->block + ((i / 2) * 4) + ((i % 2) * 32);
- for (y = 0; y < 4; ++y) {
- for (x = 0; x < 4; ++x) {
- block[x] = median;
- }
- block += 8;
- }
-
- GST_WRITE_UINT16_LE (&apx->data[i << 1], median);
- }
-
- apx->error = mve_block_error_packed (enc->mve, src, apx->block);
- return apx->error;
-}
-
-static guint32
-mve_encode_0xe (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 1-color encoding: the whole block is 1 solid color (2 bytes) */
- guint i;
- guint16 median = mve_median (enc->mve, src);
-
- for (i = 0; i < 64; ++i)
- apx->block[i] = median;
-
- apx->error = mve_block_error_packed (enc->mve, src, apx->block);
- GST_WRITE_UINT16_LE (apx->data, median);
-
- return apx->error;
-}
-
-static guint32
-mve_encode_0xf (GstMveEncoderData * enc, const guint16 * src,
- GstMveApprox * apx)
-{
- /* 2 colors dithered encoding (4 bytes) */
- guint i, x, y;
- guint32 r[2] = { 0 }, g[2] = {
- 0}, b[2] = {
- 0};
- guint16 col[2];
-
- /* find medians for both colors */
- for (y = 0; y < 8; ++y) {
- for (x = 0; x < 8; x += 2) {
- guint16 p = src[x];
-
- r[y & 1] += MVE_RVAL (p);
- g[y & 1] += MVE_GVAL (p);
- b[y & 1] += MVE_BVAL (p);
-
- p = src[x + 1];
- r[(y & 1) ^ 1] += MVE_RVAL (p);
- g[(y & 1) ^ 1] += MVE_GVAL (p);
- b[(y & 1) ^ 1] += MVE_BVAL (p);
- }
- src += enc->mve->width;
- }
- col[0] = MVE_COL ((r[0] + 16) / 32, (g[0] + 16) / 32, (b[0] + 16) / 32);
- col[1] = MVE_COL ((r[1] + 16) / 32, (g[1] + 16) / 32, (b[1] + 16) / 32);
-
- /* store block after encoding */
- for (i = 0, y = 0; y < 8; ++y) {
- for (x = 0; x < 4; ++x) {
- apx->block[i++] = col[y & 1];
- apx->block[i++] = col[(y & 1) ^ 1];
- }
- }
-
- GST_WRITE_UINT16_LE (&apx->data[0], col[0]);
- GST_WRITE_UINT16_LE (&apx->data[2], col[1]);
- apx->error = mve_block_error_packed (enc->mve,
- src - (8 * enc->mve->width), apx->block);
- return apx->error;
-}
-
-/* all available encodings in the preferred order,
- i.e. in ascending encoded size */
-static const GstMveEncoding mve_encodings[] = {
- {0x1, 0, mve_encode_0x1},
- {0x0, 0, mve_encode_0x0},
- {0x3, 1, mve_encode_0x3},
- {0x4, 1, mve_encode_0x4},
- {0x2, 1, mve_encode_0x2},
- {0xe, 2, mve_encode_0xe},
- {0x5, 2, mve_encode_0x5},
- {0xf, 4, mve_encode_0xf},
- {0x7, 6, mve_encode_0x7a},
- {0xd, 8, mve_encode_0xd},
- {0x7, 12, mve_encode_0x7b},
- {0x9, 12, mve_encode_0x9a},
- {0x9, 16, mve_encode_0x9b},
- {0x9, 16, mve_encode_0x9c},
- {0x8, 16, mve_encode_0x8a},
- {0x8, 16, mve_encode_0x8b},
- {0x8, 24, mve_encode_0x8c},
- {0x9, 24, mve_encode_0x9d},
- {0xc, 32, mve_encode_0xc},
- {0xa, 32, mve_encode_0xaa},
- {0xa, 32, mve_encode_0xab},
- {0xa, 48, mve_encode_0xac},
- {0xb, 128, mve_encode_0xb}
-};
-
-static gboolean
-mve_reorder_solution (GArray ** solution, guint16 n)
-{
- /* do a binary search to find the position to reinsert the modified element */
- /* the block we need to reconsider is always at position 0 */
- /* return TRUE if this block only has 1 encoding left and can be dropped */
- if (mve_comp_solution (&solution[0], &solution[1]) <= 0)
- return FALSE; /* already sorted */
-
- else if (solution[0]->len <= 1)
- /* drop this element from further calculations since we cannot improve here */
- return TRUE;
-
- else {
- /* we know the error value can only get worse, so we can actually start at 1 */
- guint lower = 1;
- guint upper = n - 1;
- gint cmp;
- guint idx = 0;
-
- while (upper > lower) {
- idx = lower + ((upper - lower) / 2);
-
- cmp = mve_comp_solution (&solution[0], &solution[idx]);
-
- if (cmp < 0) {
- upper = idx;
- } else if (cmp > 0) {
- lower = ++idx;
- } else {
- upper = lower = idx;
- }
- }
-
- if (idx > 0) {
- /* rearrange array members in new order */
- GArray *a = solution[0];
-
- memcpy (&solution[0], &solution[1], sizeof (GArray *) * idx);
- solution[idx] = a;
- }
- }
- return FALSE;
-}
-
-static guint32
-gst_mve_find_solution (GArray ** approx, guint16 n, guint32 size, guint16 max)
-{
- /* build an array of approximations we can shuffle around */
- GstMveApprox *sol_apx;
- GArray **solution = g_malloc (sizeof (GArray *) * n);
- GArray **current = solution;
-
- memcpy (solution, approx, sizeof (GArray *) * n);
-
- qsort (solution, n, sizeof (GArray *), mve_comp_solution);
-
- do {
- /* array is now sorted by error of the next to optimal approximation;
- drop optimal approximation for the best block */
-
- /* unable to reduce size further */
- if (current[0]->len <= 1)
- break;
-
- sol_apx = &g_array_index (current[0], GstMveApprox, current[0]->len - 1);
- size -= mve_encodings[sol_apx->type].size;
- g_array_remove_index_fast (current[0], current[0]->len - 1);
- sol_apx = &g_array_index (current[0], GstMveApprox, current[0]->len - 1);
- size += mve_encodings[sol_apx->type].size;
-
- if (mve_reorder_solution (current, n)) {
- ++current;
- --n;
- }
- } while (size > max);
-
- g_free (solution);
-
- return size;
-}
-
-GstFlowReturn
-mve_encode_frame16 (GstMveMux * mve, GstBuffer * frame, guint16 max_data)
-{
- guint16 *src;
- GstFlowReturn ret = GST_FLOW_ERROR;
- guint8 *cm = mve->chunk_code_map;
- GByteArray *pstream;
- GArray **approx;
- GstMveApprox apx;
- GstMveEncoderData enc;
- const guint16 blocks = (mve->width * mve->height) / 64;
- guint32 encoded_size = 2; /* two initial bytes for the offset */
- guint i = 0, x, y;
-
- src = (guint16 *) GST_BUFFER_DATA (frame);
-
- approx = g_malloc (sizeof (GArray *) * blocks);
-
- enc.mve = mve;
-
- for (enc.y = 0; enc.y < mve->height; enc.y += 8) {
- for (enc.x = 0; enc.x < mve->width; enc.x += 8) {
- guint32 err, last_err = MVE_APPROX_MAX_ERROR;
- guint type = 0;
- guint best = 0;
-
- enc.q2available = enc.q4available = FALSE;
- approx[i] = g_array_new (FALSE, FALSE, sizeof (GstMveApprox));
-
- do {
- err = mve_encodings[type].approx (&enc, src, &apx);
-
- if (err < last_err) {
- apx.type = best = type;
- g_array_append_val (approx[i], apx);
- last_err = err;
- }
-
- ++type;
- } while (last_err != 0);
-
- encoded_size += mve_encodings[best].size;
- ++i;
- src += 8;
- }
- src += 7 * mve->width;
- }
-
- /* find best solution with size constraints */
- GST_DEBUG_OBJECT (mve, "encoded frame %u in %u bytes (lossless)",
- mve->video_frames + 1, encoded_size);
-
-#if 0
- /* FIXME */
- src = (guint16 *) GST_BUFFER_DATA (frame);
- for (i = 0, y = 0; y < mve->height; y += 8) {
- for (x = 0; x < mve->width; x += 8, ++i) {
- GstMveApprox *sol =
- &g_array_index (approx[i], GstMveApprox, approx[i]->len - 1);
- guint opcode = mve_encodings[sol->type].opcode;
- guint j, k;
-
- if (sol->error > 0)
- GST_WARNING_OBJECT (mve, "error is %lu for %d/%d (0x%x)", sol->error, x,
- y, opcode);
-
- for (j = 0; j < 8; ++j) {
- guint16 *o = src + j * mve->width;
- guint16 *c = sol->block + j * 8;
-
- if (memcmp (o, c, 16)) {
- GST_WARNING_OBJECT (mve, "opcode 0x%x (type %d) at %d/%d, line %d:",
- opcode, sol->type, x, y, j + 1);
- for (k = 0; k < 8; ++k) {
- o = src + k * mve->width;
- c = sol->block + k * 8;
- GST_WARNING_OBJECT (mve,
- "%d should be: %4d %4d %4d %4d %4d %4d %4d %4d", k, o[0],
- o[1], o[2], o[3], o[4], o[5], o[6], o[7]);
- GST_WARNING_OBJECT (mve,
- "%d but is : %4d %4d %4d %4d %4d %4d %4d %4d", k, c[0],
- c[1], c[2], c[3], c[4], c[5], c[6], c[7]);
- }
- }
- }
- src += 8;
- }
- src += 7 * mve->width;
- }
-#endif
-
- if (encoded_size > max_data) {
- encoded_size =
- gst_mve_find_solution (approx, blocks, encoded_size, max_data);
- if (encoded_size > max_data) {
- GST_ERROR_OBJECT (mve, "unable to compress frame to less than %d bytes",
- encoded_size);
- for (i = 0; i < blocks; ++i)
- g_array_free (approx[i], TRUE);
-
- goto done;
- }
- GST_DEBUG_OBJECT (mve, "compressed frame %u to %u bytes (lossy)",
- mve->video_frames + 1, encoded_size);
- }
-
- mve->chunk_video = g_byte_array_sized_new (encoded_size);
- /* reserve two bytes for the offset pointer we'll fill in later */
- g_byte_array_set_size (mve->chunk_video, 2);
-
- pstream = g_byte_array_new ();
-
- /* encode */
- src = (guint16 *) GST_BUFFER_DATA (frame);
- for (i = 0, y = 0; y < mve->height; y += 8) {
- for (x = 0; x < mve->width; x += 8, ++i) {
- GstMveApprox *sol =
- &g_array_index (approx[i], GstMveApprox, approx[i]->len - 1);
- guint opcode = mve_encodings[sol->type].opcode;
- GByteArray *dest;
-
- if (opcode >= 0x2 && opcode <= 0x4)
- dest = pstream;
- else
- dest = mve->chunk_video;
-
- g_byte_array_append (dest, sol->data, mve_encodings[sol->type].size);
-
- if (i & 1) {
- *cm |= opcode << 4;
- ++cm;
- } else
- *cm = opcode;
-
- /* modify the frame to match the image we actually encoded */
- if (sol->error > 0)
- mve_restore_block (mve, src, sol->block);
-
- src += 8;
- g_array_free (approx[i], TRUE);
- }
- src += 7 * mve->width;
- }
-
- /* now update the offset */
- GST_WRITE_UINT16_LE (mve->chunk_video->data, mve->chunk_video->len);
- g_byte_array_append (mve->chunk_video, pstream->data, pstream->len);
- g_byte_array_free (pstream, TRUE);
-
- ret = GST_FLOW_OK;
-
-done:
- g_free (approx);
-
- return ret;
-}