summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/msn/webcam/libmimic/mimic.c
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/msn/webcam/libmimic/mimic.c')
-rw-r--r--kopete/protocols/msn/webcam/libmimic/mimic.c334
1 files changed, 334 insertions, 0 deletions
diff --git a/kopete/protocols/msn/webcam/libmimic/mimic.c b/kopete/protocols/msn/webcam/libmimic/mimic.c
new file mode 100644
index 00000000..95564755
--- /dev/null
+++ b/kopete/protocols/msn/webcam/libmimic/mimic.c
@@ -0,0 +1,334 @@
+/* Copyright (C) 2005 Ole André Vadla Ravnås <oleavr@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+#include "mimic-private.h"
+
+/**
+ * Creates a new instance and returns a pointer to the new context
+ * that can be used for either encoding or decoding by calling
+ * #mimic_encoder_init or #mimic_decoder_init.
+ *
+ * #mimic_close is called to free any resources associated with
+ * the context once done.
+ *
+ * @returns a new mimic context
+ */
+MimCtx *mimic_open()
+{
+ MimCtx *ctx;
+
+ ctx = g_new0(MimCtx, 1);
+
+ ctx->encoder_initialized = FALSE;
+ ctx->decoder_initialized = FALSE;
+
+ return ctx;
+}
+
+/**
+ * Frees any resources associated with the given context.
+ *
+ * @param ctx the mimic context to free
+ */
+void mimic_close(MimCtx *ctx)
+{
+ if (ctx->encoder_initialized || ctx->decoder_initialized) {
+ gint i;
+
+ g_free(ctx->cur_frame_buf);
+
+ for (i = 0; i < 16; i++)
+ g_free(ctx->buf_ptrs[i]);
+ }
+
+ g_free(ctx);
+}
+
+/*
+ * mimic_init
+ *
+ * Internal helper-function used to initialize
+ * a given context.
+ */
+static void mimic_init(MimCtx *ctx, gint width, gint height)
+{
+ gint bufsize, i;
+
+ /*
+ * Dimensions-related.
+ */
+ ctx->frame_width = width;
+ ctx->frame_height = height;
+
+ ctx->y_stride = ctx->frame_width;
+ ctx->y_row_count = ctx->frame_height;
+ ctx->y_size = ctx->y_stride * ctx->y_row_count;
+
+ ctx->crcb_stride = ctx->y_stride / 2;
+ ctx->crcb_row_count = ctx->y_row_count / 2;
+ ctx->crcb_size = ctx->crcb_stride * ctx->crcb_row_count;
+
+ ctx->num_vblocks_y = ctx->frame_height / 8;
+ ctx->num_hblocks_y = ctx->frame_width / 8;
+
+ ctx->num_vblocks_cbcr = ctx->frame_height / 16;
+ ctx->num_hblocks_cbcr = ctx->frame_width / 16;
+
+ if (ctx->frame_height % 16 != 0)
+ ctx->num_vblocks_cbcr++;
+
+ /*
+ * Initialize state.
+ */
+ ctx->frame_num = 0;
+ ctx->ptr_index = 15;
+ ctx->num_coeffs = 28;
+
+ /*
+ * Allocate memory for buffers.
+ */
+ ctx->cur_frame_buf = g_new(guchar, (320 * 240 * 3) / 2);
+
+ bufsize = ctx->y_size + (ctx->crcb_size * 2);
+ for (i = 0; i < 16; i++)
+ ctx->buf_ptrs[i] = g_new(guchar, bufsize);
+
+ /*
+ * Initialize vlc lookup used by decoder.
+ */
+ _initialize_vlcdec_lookup(ctx->vlcdec_lookup);
+}
+
+/**
+ * Initialize the mimic encoder and prepare for encoding by
+ * initializing internal state and allocating resources as
+ * needed.
+ *
+ * After initializing use #mimic_get_property to determine
+ * the size of the output buffer needed for calls to
+ * #mimic_encode_frame. Use #mimic_set_property to set
+ * encoding quality.
+ *
+ * Note that once a given context has been initialized
+ * for either encoding or decoding it is not possible
+ * to initialize it again.
+ *
+ * @param ctx the mimic context to initialize
+ * @param resolution a #MimicResEnum used to specify the resolution
+ * @returns #TRUE on success
+ */
+gboolean mimic_encoder_init(MimCtx *ctx, const MimicResEnum resolution)
+{
+ gint width, height;
+
+ /* Check if we've been initialized before. */
+ if (ctx->encoder_initialized || ctx->decoder_initialized)
+ return FALSE;
+
+ /* Check resolution. */
+ if (resolution == MIMIC_RES_LOW) {
+ width = 160;
+ height = 120;
+ } else if (resolution == MIMIC_RES_HIGH) {
+ width = 320;
+ height = 240;
+ } else {
+ return FALSE;
+ }
+
+ /* Initialize! */
+ mimic_init(ctx, width, height);
+
+ /* Set a default quality setting. */
+ ctx->quality = ENCODER_QUALITY_DEFAULT;
+
+ ctx->encoder_initialized = TRUE;
+
+ return TRUE;
+}
+
+/**
+ * Initialize the mimic decoder. The frame passed in frame_buffer
+ * is used to determine the resolution so that the internal state
+ * can be prepared and resources allocated accordingly. Note that
+ * the frame passed has to be a keyframe.
+ *
+ * After initializing use #mimic_get_property to determine required
+ * buffer-size, resolution, quality, etc.
+ *
+ * Note that once a given context has been initialized
+ * for either encoding or decoding it is not possible
+ * to initialize it again.
+ *
+ * @param ctx the mimic context to initialize
+ * @param frame_buffer buffer containing the first frame to decode
+ * @returns #TRUE on success
+ */
+gboolean mimic_decoder_init(MimCtx *ctx, const guchar *frame_buffer)
+{
+ gint width, height;
+ gboolean is_keyframe;
+
+ /* Check if we've been initialized before and that
+ * frame_buffer is not NULL. */
+ if (ctx->encoder_initialized || ctx->decoder_initialized ||
+ frame_buffer == NULL)
+ {
+ return FALSE;
+ }
+
+ /* Check resolution. */
+ width = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 4)));
+ height = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 6)));
+
+ if (!(width == 160 && height == 120) && !(width == 320 && height == 240))
+ return FALSE;
+
+ /* Check that we're initialized with a keyframe. */
+ is_keyframe = (GUINT32_FROM_LE(*((guint32 *) (frame_buffer + 12))) == 0);
+
+ if (!is_keyframe)
+ return FALSE;
+
+ /* Get quality setting (in case we get queried for it before decoding). */
+ ctx->quality = GUINT16_FROM_LE(*((guint16 *) (frame_buffer + 2)));
+
+ /* Initialize! */
+ mimic_init(ctx, width, height);
+
+ ctx->decoder_initialized = TRUE;
+
+ return TRUE;
+}
+
+/**
+ * Get a property from a given mimic context. The context
+ * has to be initialized.
+ *
+ * Currently the following properties are defined:
+ * - "buffer_size"
+ * - Required output buffer size
+ * - "width"
+ * - Frame width
+ * - "height"
+ * - Frame height
+ * - "quality"
+ * - Encoder: Encoding quality used
+ * - Decoder: Decoding quality of the last known frame
+ *
+ * @param ctx the mimic context to retrieve the property from
+ * @param name of the property to retrieve the current value of
+ * @param data pointer to the data that will receive the retrieved value
+ * @returns #TRUE on success
+ */
+gboolean mimic_get_property(MimCtx *ctx, const gchar *name, gpointer data)
+{
+ /* Either the encoder or the decoder has to be initialized. */
+ if (!ctx->encoder_initialized && !ctx->decoder_initialized)
+ return FALSE;
+
+ if (ctx->encoder_initialized) {
+
+ if (strcmp(name, "buffer_size") == 0) {
+ *((gint *) data) = ENCODER_BUFFER_SIZE;
+
+ return TRUE;
+ }
+
+ } else { /* decoder_initialized */
+
+ if (strcmp(name, "buffer_size") == 0) {
+ *((gint *) data) = ctx->frame_width * ctx->frame_height * 3;
+
+ return TRUE;
+ }
+ }
+
+ if (strcmp(name, "width") == 0) {
+ *((gint *) data) = ctx->frame_width;
+
+ return TRUE;
+ } else if (strcmp(name, "height") == 0) {
+ *((gint *) data) = ctx->frame_height;
+
+ return TRUE;
+ } else if (strcmp(name, "quality") == 0) {
+ *((gint *) data) = ctx->quality;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Set a property in a given mimic context. The context
+ * has to be initialized.
+ *
+ * Currently the following properties are defined:
+ * - "quality"
+ * - Encoding quality used by encoder.
+ *
+ * @param ctx the mimic context to set a property in
+ * @param name of the property to set to a new value
+ * @param data pointer to the data that contains the new value
+ * @returns #TRUE on success
+ */
+gboolean mimic_set_property(MimCtx *ctx, const gchar *name, gpointer data)
+{
+ /* Either the encoder or the decoder has to be initialized. */
+ if (!ctx->encoder_initialized && !ctx->decoder_initialized)
+ return FALSE;
+
+ if (ctx->encoder_initialized) {
+
+ if (strcmp(name, "quality") == 0) {
+ gint new_quality = *((gint *) data);
+
+ if (new_quality < ENCODER_QUALITY_MIN ||
+ new_quality > ENCODER_QUALITY_MAX)
+ {
+ return FALSE;
+ }
+
+ ctx->quality = new_quality;
+
+ return TRUE;
+ }
+
+ } else { /* decoder_initialized */ }
+
+ return FALSE;
+}
+
+/*
+ * _clamp_value
+ *
+ * Internal helper-function used to clamp a given
+ * value to the range [ 0, 255 ].
+ */
+guchar _clamp_value(gint value)
+{
+ if (value < 0)
+ return 0;
+ else if (value > 255)
+ return 255;
+ else
+ return value;
+}
+