~ubuntu-branches/ubuntu/gutsy/amsn/gutsy

« back to all changes in this revision

Viewing changes to utils/webcamsn/src/decode.c

  • Committer: Bazaar Package Importer
  • Author(s): Theodore Karkoulis
  • Date: 2006-01-04 15:26:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060104152602-ipe1yg00rl3nlklv
Tags: 0.95-1
New Upstream Release (closes: #345052, #278575).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2005  Ole Andr� Vadla Ravn�s <oleavr@gmail.com>
 
2
 *
 
3
 * This library is free software; you can redistribute it and/or
 
4
 * modify it under the terms of the GNU Lesser General Public
 
5
 * License as published by the Free Software Foundation; either
 
6
 * version 2.1 of the License, or (at your option) any later version.
 
7
 *
 
8
 * This library is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
11
 * Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public
 
14
 * License along with this library; if not, write to the Free Software
 
15
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 */
 
17
 
 
18
#include <string.h>
 
19
#include "mimic-private.h"
 
20
 
 
21
static gboolean decode(MimCtx *ctx, gboolean is_pframe);
 
22
 
 
23
/**
 
24
 * Decode a MIMIC-encoded frame into RGB data.
 
25
 *
 
26
 * @param ctx the mimic context
 
27
 * @param input_buffer buffer containing the MIMIC-encoded frame to decode
 
28
 * @param output_buffer buffer that will receive the decoded frame in RGB 24-bpp packed pixel top-down format
 
29
 *                      (use #mimic_get_property to determine the required buffer size, as well as frame width and height)
 
30
 * @returns #TRUE on success
 
31
 */
 
32
gboolean mimic_decode_frame(MimCtx *ctx,
 
33
                            const guchar *input_buffer,
 
34
                            guchar *output_buffer)
 
35
{
 
36
    gboolean result, is_pframe;
 
37
    guchar *input_y, *input_cr, *input_cb;
 
38
    gint width, height;
 
39
    
 
40
    /*
 
41
     * Some sanity checks.
 
42
     */
 
43
    if (ctx == NULL || input_buffer == NULL || output_buffer == NULL)
 
44
    {
 
45
        return FALSE;
 
46
    }
 
47
 
 
48
    if (!ctx->decoder_initialized)
 
49
        return FALSE;
 
50
    
 
51
    /*
 
52
     * Get frame dimensions.
 
53
     */
 
54
    width  = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 4)));
 
55
    height = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 6)));
 
56
 
 
57
    /*
 
58
     * Resolution changing is not supported.
 
59
     */
 
60
    if (width  != ctx->frame_width ||
 
61
        height != ctx->frame_height)
 
62
    {
 
63
        return FALSE;
 
64
    }
 
65
    
 
66
    /*
 
67
     * Increment frame counter.
 
68
     */
 
69
    ctx->frame_num++;
 
70
 
 
71
    /*
 
72
     * Initialize state.
 
73
     */
 
74
    ctx->quality = GUINT16_FROM_LE(*((guint16 *) (input_buffer + 2)));
 
75
    is_pframe = GUINT32_FROM_LE(*((guint32 *) (input_buffer + 12)));
 
76
    ctx->num_coeffs = input_buffer[16];
 
77
    
 
78
    ctx->data_buffer = (gchar *) (input_buffer + 20);
 
79
    ctx->data_index = 0;
 
80
    ctx->cur_chunk_len = 16;
 
81
    ctx->read_odd = FALSE;
 
82
    
 
83
    /*
 
84
     * Decode frame.
 
85
     */
 
86
    if (!(is_pframe && ctx->prev_frame_buf == NULL))
 
87
        result = decode(ctx, is_pframe);
 
88
    else
 
89
        result = FALSE;
 
90
 
 
91
    /*
 
92
     * Perform YUV 420 to RGB conversion.
 
93
     */
 
94
    input_y = ctx->cur_frame_buf;
 
95
    input_cr = ctx->cur_frame_buf + ctx->y_size;
 
96
    input_cb = ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size;
 
97
 
 
98
    _yuv_to_rgb(input_y,
 
99
                input_cb,
 
100
                input_cr,
 
101
                output_buffer,
 
102
                ctx->frame_width,
 
103
                ctx->frame_height);
 
104
 
 
105
    return result;
 
106
}
 
107
 
 
108
/*
 
109
 * decode_main
 
110
 *
 
111
 * Main decoding loop.
 
112
 */
 
113
static gboolean decode(MimCtx *ctx, gboolean is_pframe)
 
114
{
 
115
    gint y, x, i, j, chrom_ch, *bptr, base_offset, offset;
 
116
    gint dct_block[64];
 
117
    guchar *src, *dst, *p;
 
118
    guint32 bit;
 
119
    
 
120
    /*
 
121
     * Clear Cr and Cb planes.
 
122
     */
 
123
    p = ctx->cur_frame_buf + ctx->y_size;
 
124
    memset(p, 128, 2 * ctx->crcb_size);
 
125
 
 
126
    /*
 
127
     * Decode Y plane.
 
128
     */
 
129
    for (y = 0; y < ctx->num_vblocks_y; y++) {
 
130
 
 
131
        base_offset = ctx->y_stride * 8 * y;
 
132
 
 
133
        src = ctx->prev_frame_buf + base_offset;
 
134
        dst = ctx->cur_frame_buf  + base_offset;
 
135
 
 
136
        for (x = 0; x < ctx->num_hblocks_y; x++) {
 
137
 
 
138
            /* Check for a change condition in the current block. */
 
139
 
 
140
            if (is_pframe)
 
141
                bit = _read_bits(ctx, 1);
 
142
            else
 
143
                bit = 0;
 
144
 
 
145
            if (bit == 0) {
 
146
 
 
147
                /* Yes: Is the new content the same as it was in one of
 
148
                 * the 15 last frames preceding the previous? */
 
149
                
 
150
                if (is_pframe)
 
151
                    bit = _read_bits(ctx, 1);
 
152
 
 
153
                if (bit == 0) {
 
154
 
 
155
                    /* No: decode it. */
 
156
                    
 
157
                    if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) {
 
158
 
 
159
                        /* Corruped frame, return. */
 
160
                        return FALSE;
 
161
                    }
 
162
 
 
163
                    _idct_dequant_block(ctx, dct_block, 0);
 
164
 
 
165
                    bptr = dct_block;
 
166
                    for (i = 0; i < 8; i++) {
 
167
                        offset = ctx->y_stride * i;
 
168
 
 
169
                        for (j = 0; j < 8; j++) {
 
170
                            guint v;
 
171
                            
 
172
                            if (bptr[j] <= 255)
 
173
                                v = (bptr[j] >= 0) ? bptr[j] : 0;
 
174
                            else
 
175
                                v = 255;
 
176
                            
 
177
                            *(dst + offset + j) = v;
 
178
                        }
 
179
 
 
180
                        bptr += 8;
 
181
                    }
 
182
                } else {
 
183
                    guint32 backref;
 
184
                    
 
185
                    /* Yes: read the backreference (4 bits) and copy. */
 
186
 
 
187
                    backref = _read_bits(ctx, 4);
 
188
 
 
189
                    p = ctx->buf_ptrs[(ctx->ptr_index + backref) % 16];
 
190
                    p += base_offset + (x * 8);
 
191
 
 
192
                    for (i = 0; i < 8; i++) {
 
193
                        offset = ctx->y_stride * i;
 
194
 
 
195
                        memcpy(dst + offset, p + offset, 8);
 
196
                    }
 
197
                }
 
198
            } else {
 
199
                
 
200
                /* No change no worries: just copy from the previous frame. */
 
201
 
 
202
                for (i = 0; i < 8; i++) {
 
203
                    offset = ctx->y_stride * i;
 
204
 
 
205
                    memcpy(dst + offset, src + offset, 8);
 
206
                }
 
207
            }
 
208
 
 
209
            src += 8;
 
210
            dst += 8;
 
211
        }
 
212
    }
 
213
 
 
214
    /*
 
215
     * Decode Cr and Cb planes.
 
216
     */
 
217
    for (chrom_ch = 0; chrom_ch < 2; chrom_ch++) {
 
218
 
 
219
        base_offset = ctx->y_size + (ctx->crcb_size * chrom_ch);
 
220
 
 
221
        for (y = 0; y < ctx->num_vblocks_cbcr; y++) {
 
222
            guint num_rows = 8;
 
223
            
 
224
            /* The last row of blocks in chrominance for 160x120 resolution
 
225
             * is half the normal height and must be accounted for. */
 
226
            if (y + 1 == ctx->num_vblocks_cbcr && ctx->frame_height % 16 != 0)
 
227
                num_rows = 4;
 
228
 
 
229
            offset = base_offset + (ctx->crcb_stride * 8 * y);
 
230
 
 
231
            src = ctx->prev_frame_buf + offset;
 
232
            dst = ctx->cur_frame_buf  + offset;
 
233
            
 
234
            for (x = 0; x < ctx->num_hblocks_cbcr; x++) {
 
235
                
 
236
                /* Check for a change condition in the current block. */
 
237
                
 
238
                if (is_pframe)
 
239
                    bit = _read_bits(ctx, 1);
 
240
                else
 
241
                    bit = 1;
 
242
 
 
243
                if (bit == 1) {
 
244
                    
 
245
                    /* Yes: decode it. */
 
246
 
 
247
                    if (_vlc_decode_block(ctx, dct_block, ctx->num_coeffs) == FALSE) {
 
248
 
 
249
                        /* Corrupted frame: clear Cr and Cb planes and return. */
 
250
                        p = ctx->cur_frame_buf + ctx->y_size;
 
251
                        memset(p, 128, ctx->crcb_size * 2);
 
252
 
 
253
                        return FALSE;
 
254
                    }
 
255
 
 
256
                    _idct_dequant_block(ctx, dct_block, 1);
 
257
 
 
258
                    for (i = 0; i < num_rows; i++) {
 
259
                        p = dst + (ctx->crcb_stride * i);
 
260
 
 
261
                        for (j = 0; j < 8; j++)
 
262
                            p[j] = dct_block[(i * 8) + j];
 
263
                    }
 
264
 
 
265
                } else {
 
266
 
 
267
                    /* No change no worries: just copy from the previous frame. */
 
268
                    
 
269
                    for (i = 0; i < num_rows; i++) {
 
270
                        offset = ctx->crcb_stride * i;
 
271
                        
 
272
                        memcpy(dst + offset, src + offset, 8);
 
273
                    }
 
274
                }
 
275
 
 
276
                src += 8;
 
277
                dst += 8;
 
278
            }
 
279
        }
 
280
    }
 
281
 
 
282
    /*
 
283
     * Make a copy of the current frame and store in
 
284
     * the circular pointer list of 16 entries.
 
285
     */
 
286
    ctx->prev_frame_buf = ctx->buf_ptrs[ctx->ptr_index];
 
287
    memcpy(ctx->prev_frame_buf, ctx->cur_frame_buf,
 
288
           ctx->y_size + (ctx->crcb_size * 2));
 
289
    
 
290
    if (--ctx->ptr_index < 0)
 
291
        ctx->ptr_index = 15;
 
292
    
 
293
    /*
 
294
     * Perform deblocking on all planes.
 
295
     */
 
296
    _deblock(ctx->cur_frame_buf,
 
297
             ctx->y_stride, ctx->y_row_count);
 
298
    
 
299
    _deblock(ctx->cur_frame_buf + ctx->y_size,
 
300
             ctx->crcb_stride, ctx->crcb_row_count);
 
301
    
 
302
    _deblock(ctx->cur_frame_buf + ctx->y_size + ctx->crcb_size,
 
303
             ctx->crcb_stride, ctx->crcb_row_count);
 
304
 
 
305
    return TRUE;
 
306
}
 
307