diff options
Diffstat (limited to 'kopete/protocols/msn/webcam/libmimic/mimic.c')
-rw-r--r-- | kopete/protocols/msn/webcam/libmimic/mimic.c | 334 |
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; +} + |