~ubuntu-branches/ubuntu/raring/libav/raring-security

« back to all changes in this revision

Viewing changes to .pc/post-0.7.1/0022-Fix-incorrect-max_lowres-values.patch/libavcodec/cdgraphics.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2011-09-28 09:18:34 UTC
  • mfrom: (1.3.7 sid)
  • Revision ID: package-import@ubuntu.com-20110928091834-w415mnuh06h4zpvc
Tags: 4:0.7.1-7ubuntu2
Revert "Convert package to include multiarch support."

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * CD Graphics Video Decoder
 
3
 * Copyright (c) 2009 Michael Tison
 
4
 *
 
5
 * This file is part of Libav.
 
6
 *
 
7
 * Libav is free software; you can redistribute it and/or
 
8
 * modify it under the terms of the GNU Lesser General Public
 
9
 * License as published by the Free Software Foundation; either
 
10
 * version 2.1 of the License, or (at your option) any later version.
 
11
 *
 
12
 * Libav is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
 * Lesser General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU Lesser General Public
 
18
 * License along with Libav; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
20
 */
 
21
 
 
22
#include "avcodec.h"
 
23
#include "bytestream.h"
 
24
 
 
25
/**
 
26
 * @file
 
27
 * @brief CD Graphics Video Decoder
 
28
 * @author Michael Tison
 
29
 * @sa http://wiki.multimedia.cx/index.php?title=CD_Graphics
 
30
 * @sa http://www.ccs.neu.edu/home/bchafy/cdb/info/cdg
 
31
 */
 
32
 
 
33
/// default screen sizes
 
34
#define CDG_FULL_WIDTH           300
 
35
#define CDG_FULL_HEIGHT          216
 
36
#define CDG_DISPLAY_WIDTH        294
 
37
#define CDG_DISPLAY_HEIGHT       204
 
38
#define CDG_BORDER_WIDTH           6
 
39
#define CDG_BORDER_HEIGHT         12
 
40
 
 
41
/// masks
 
42
#define CDG_COMMAND             0x09
 
43
#define CDG_MASK                0x3F
 
44
 
 
45
/// instruction codes
 
46
#define CDG_INST_MEMORY_PRESET     1
 
47
#define CDG_INST_BORDER_PRESET     2
 
48
#define CDG_INST_TILE_BLOCK        6
 
49
#define CDG_INST_SCROLL_PRESET    20
 
50
#define CDG_INST_SCROLL_COPY      24
 
51
#define CDG_INST_LOAD_PAL_LO      30
 
52
#define CDG_INST_LOAD_PAL_HIGH    31
 
53
#define CDG_INST_TILE_BLOCK_XOR   38
 
54
 
 
55
/// data sizes
 
56
#define CDG_PACKET_SIZE           24
 
57
#define CDG_DATA_SIZE             16
 
58
#define CDG_TILE_HEIGHT           12
 
59
#define CDG_TILE_WIDTH             6
 
60
#define CDG_MINIMUM_PKT_SIZE       6
 
61
#define CDG_MINIMUM_SCROLL_SIZE    3
 
62
#define CDG_HEADER_SIZE            8
 
63
#define CDG_PALETTE_SIZE          16
 
64
 
 
65
typedef struct CDGraphicsContext {
 
66
    AVFrame frame;
 
67
    int hscroll;
 
68
    int vscroll;
 
69
} CDGraphicsContext;
 
70
 
 
71
static void cdg_init_frame(AVFrame *frame)
 
72
{
 
73
    avcodec_get_frame_defaults(frame);
 
74
    frame->reference = 3;
 
75
    frame->buffer_hints = FF_BUFFER_HINTS_VALID    |
 
76
                          FF_BUFFER_HINTS_READABLE |
 
77
                          FF_BUFFER_HINTS_PRESERVE |
 
78
                          FF_BUFFER_HINTS_REUSABLE;
 
79
}
 
80
 
 
81
static av_cold int cdg_decode_init(AVCodecContext *avctx)
 
82
{
 
83
    CDGraphicsContext *cc = avctx->priv_data;
 
84
 
 
85
    cdg_init_frame(&cc->frame);
 
86
 
 
87
    avctx->width   = CDG_FULL_WIDTH;
 
88
    avctx->height  = CDG_FULL_HEIGHT;
 
89
    avctx->pix_fmt = PIX_FMT_PAL8;
 
90
 
 
91
    return 0;
 
92
}
 
93
 
 
94
static void cdg_border_preset(CDGraphicsContext *cc, uint8_t *data)
 
95
{
 
96
    int y;
 
97
    int lsize    = cc->frame.linesize[0];
 
98
    uint8_t *buf = cc->frame.data[0];
 
99
    int color    = data[0] & 0x0F;
 
100
 
 
101
    if (!(data[1] & 0x0F)) {
 
102
        /// fill the top and bottom borders
 
103
        memset(buf, color, CDG_BORDER_HEIGHT * lsize);
 
104
        memset(buf + (CDG_FULL_HEIGHT - CDG_BORDER_HEIGHT) * lsize,
 
105
               color, CDG_BORDER_HEIGHT * lsize);
 
106
 
 
107
        /// fill the side borders
 
108
        for (y = CDG_BORDER_HEIGHT; y < CDG_FULL_HEIGHT - CDG_BORDER_HEIGHT; y++) {
 
109
            memset(buf + y * lsize, color, CDG_BORDER_WIDTH);
 
110
            memset(buf + CDG_FULL_WIDTH - CDG_BORDER_WIDTH + y * lsize,
 
111
                   color, CDG_BORDER_WIDTH);
 
112
        }
 
113
    }
 
114
}
 
115
 
 
116
static void cdg_load_palette(CDGraphicsContext *cc, uint8_t *data, int low)
 
117
{
 
118
    uint8_t r, g, b;
 
119
    uint16_t color;
 
120
    int i;
 
121
    int array_offset  = low ? 0 : 8;
 
122
    uint32_t *palette = (uint32_t *) cc->frame.data[1];
 
123
 
 
124
    for (i = 0; i < 8; i++) {
 
125
        color = (data[2 * i] << 6) + (data[2 * i + 1] & 0x3F);
 
126
        r = ((color >> 8) & 0x000F) * 17;
 
127
        g = ((color >> 4) & 0x000F) * 17;
 
128
        b = ((color     ) & 0x000F) * 17;
 
129
        palette[i + array_offset] = r << 16 | g << 8 | b;
 
130
    }
 
131
    cc->frame.palette_has_changed = 1;
 
132
}
 
133
 
 
134
static int cdg_tile_block(CDGraphicsContext *cc, uint8_t *data, int b)
 
135
{
 
136
    unsigned ci, ri;
 
137
    int color;
 
138
    int x, y;
 
139
    int ai;
 
140
    int stride   = cc->frame.linesize[0];
 
141
    uint8_t *buf = cc->frame.data[0];
 
142
 
 
143
    ri = (data[2] & 0x1F) * CDG_TILE_HEIGHT + cc->vscroll;
 
144
    ci = (data[3] & 0x3F) * CDG_TILE_WIDTH  + cc->hscroll;
 
145
 
 
146
    if (ri > (CDG_FULL_HEIGHT - CDG_TILE_HEIGHT))
 
147
        return AVERROR(EINVAL);
 
148
    if (ci > (CDG_FULL_WIDTH - CDG_TILE_WIDTH))
 
149
        return AVERROR(EINVAL);
 
150
 
 
151
    for (y = 0; y < CDG_TILE_HEIGHT; y++) {
 
152
        for (x = 0; x < CDG_TILE_WIDTH; x++) {
 
153
            if (!((data[4 + y] >> (5 - x)) & 0x01))
 
154
                color = data[0] & 0x0F;
 
155
            else
 
156
                color = data[1] & 0x0F;
 
157
 
 
158
            ai = ci + x + (stride * (ri + y));
 
159
            if (b)
 
160
                color ^= buf[ai];
 
161
            buf[ai] = color;
 
162
        }
 
163
    }
 
164
 
 
165
    return 0;
 
166
}
 
167
 
 
168
#define UP    2
 
169
#define DOWN  1
 
170
#define LEFT  2
 
171
#define RIGHT 1
 
172
 
 
173
static void cdg_copy_rect_buf(int out_tl_x, int out_tl_y, uint8_t *out,
 
174
                              int in_tl_x, int in_tl_y, uint8_t *in,
 
175
                              int w, int h, int stride)
 
176
{
 
177
    int y;
 
178
 
 
179
    in  += in_tl_x  + in_tl_y  * stride;
 
180
    out += out_tl_x + out_tl_y * stride;
 
181
    for (y = 0; y < h; y++)
 
182
        memcpy(out + y * stride, in + y * stride, w);
 
183
}
 
184
 
 
185
static void cdg_fill_rect_preset(int tl_x, int tl_y, uint8_t *out,
 
186
                                 int color, int w, int h, int stride)
 
187
{
 
188
    int y;
 
189
 
 
190
    for (y = tl_y; y < tl_y + h; y++)
 
191
        memset(out + tl_x + y * stride, color, w);
 
192
}
 
193
 
 
194
static void cdg_fill_wrapper(int out_tl_x, int out_tl_y, uint8_t *out,
 
195
                             int in_tl_x, int in_tl_y, uint8_t *in,
 
196
                             int color, int w, int h, int stride, int roll)
 
197
{
 
198
    if (roll) {
 
199
        cdg_copy_rect_buf(out_tl_x, out_tl_y, out, in_tl_x, in_tl_y,
 
200
                          in, w, h, stride);
 
201
    } else {
 
202
        cdg_fill_rect_preset(out_tl_x, out_tl_y, out, color, w, h, stride);
 
203
    }
 
204
}
 
205
 
 
206
static void cdg_scroll(CDGraphicsContext *cc, uint8_t *data,
 
207
                       AVFrame *new_frame, int roll_over)
 
208
{
 
209
    int color;
 
210
    int hscmd, h_off, hinc, vscmd, v_off, vinc;
 
211
    int y;
 
212
    int stride   = cc->frame.linesize[0];
 
213
    uint8_t *in  = cc->frame.data[0];
 
214
    uint8_t *out = new_frame->data[0];
 
215
 
 
216
    color =  data[0] & 0x0F;
 
217
    hscmd = (data[1] & 0x30) >> 4;
 
218
    vscmd = (data[2] & 0x30) >> 4;
 
219
 
 
220
    h_off =  FFMIN(data[1] & 0x07, CDG_BORDER_WIDTH  - 1);
 
221
    v_off =  FFMIN(data[2] & 0x07, CDG_BORDER_HEIGHT - 1);
 
222
 
 
223
    /// find the difference and save the offset for cdg_tile_block usage
 
224
    hinc = h_off - cc->hscroll;
 
225
    vinc = v_off - cc->vscroll;
 
226
    cc->hscroll = h_off;
 
227
    cc->vscroll = v_off;
 
228
 
 
229
    if (vscmd == UP)
 
230
        vinc -= 12;
 
231
    if (vscmd == DOWN)
 
232
        vinc += 12;
 
233
    if (hscmd == LEFT)
 
234
        hinc -= 6;
 
235
    if (hscmd == RIGHT)
 
236
        hinc += 6;
 
237
 
 
238
    if (!hinc && !vinc)
 
239
        return;
 
240
 
 
241
    memcpy(new_frame->data[1], cc->frame.data[1], CDG_PALETTE_SIZE * 4);
 
242
 
 
243
    for (y = FFMAX(0, vinc); y < FFMIN(CDG_FULL_HEIGHT + vinc, CDG_FULL_HEIGHT); y++)
 
244
        memcpy(out + FFMAX(0, hinc) + stride * y,
 
245
               in + FFMAX(0, hinc) - hinc + (y - vinc) * stride,
 
246
               FFMIN(stride + hinc, stride));
 
247
 
 
248
    if (vinc > 0)
 
249
        cdg_fill_wrapper(0, 0, out,
 
250
                         0, CDG_FULL_HEIGHT - vinc, in, color,
 
251
                         stride, vinc, stride, roll_over);
 
252
    else if (vinc < 0)
 
253
        cdg_fill_wrapper(0, CDG_FULL_HEIGHT + vinc, out,
 
254
                         0, 0, in, color,
 
255
                         stride, -1 * vinc, stride, roll_over);
 
256
 
 
257
    if (hinc > 0)
 
258
        cdg_fill_wrapper(0, 0, out,
 
259
                         CDG_FULL_WIDTH - hinc, 0, in, color,
 
260
                         hinc, CDG_FULL_HEIGHT, stride, roll_over);
 
261
    else if (hinc < 0)
 
262
        cdg_fill_wrapper(CDG_FULL_WIDTH + hinc, 0, out,
 
263
                         0, 0, in, color,
 
264
                         -1 * hinc, CDG_FULL_HEIGHT, stride, roll_over);
 
265
 
 
266
}
 
267
 
 
268
static int cdg_decode_frame(AVCodecContext *avctx,
 
269
                            void *data, int *data_size, AVPacket *avpkt)
 
270
{
 
271
    const uint8_t *buf = avpkt->data;
 
272
    int buf_size       = avpkt->size;
 
273
    int ret;
 
274
    uint8_t command, inst;
 
275
    uint8_t cdg_data[CDG_DATA_SIZE];
 
276
    AVFrame new_frame;
 
277
    CDGraphicsContext *cc = avctx->priv_data;
 
278
 
 
279
    if (buf_size < CDG_MINIMUM_PKT_SIZE) {
 
280
        av_log(avctx, AV_LOG_ERROR, "buffer too small for decoder\n");
 
281
        return AVERROR(EINVAL);
 
282
    }
 
283
 
 
284
    ret = avctx->reget_buffer(avctx, &cc->frame);
 
285
    if (ret) {
 
286
        av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
 
287
        return ret;
 
288
    }
 
289
 
 
290
    command = bytestream_get_byte(&buf);
 
291
    inst    = bytestream_get_byte(&buf);
 
292
    inst    &= CDG_MASK;
 
293
    buf += 2;  /// skipping 2 unneeded bytes
 
294
    bytestream_get_buffer(&buf, cdg_data, buf_size - CDG_HEADER_SIZE);
 
295
 
 
296
    if ((command & CDG_MASK) == CDG_COMMAND) {
 
297
        switch (inst) {
 
298
        case CDG_INST_MEMORY_PRESET:
 
299
            if (!(cdg_data[1] & 0x0F))
 
300
                memset(cc->frame.data[0], cdg_data[0] & 0x0F,
 
301
                       cc->frame.linesize[0] * CDG_FULL_HEIGHT);
 
302
            break;
 
303
        case CDG_INST_LOAD_PAL_LO:
 
304
        case CDG_INST_LOAD_PAL_HIGH:
 
305
            if (buf_size - CDG_HEADER_SIZE < CDG_DATA_SIZE) {
 
306
                av_log(avctx, AV_LOG_ERROR, "buffer too small for loading palette\n");
 
307
                return AVERROR(EINVAL);
 
308
            }
 
309
 
 
310
            cdg_load_palette(cc, cdg_data, inst == CDG_INST_LOAD_PAL_LO);
 
311
            break;
 
312
        case CDG_INST_BORDER_PRESET:
 
313
            cdg_border_preset(cc, cdg_data);
 
314
            break;
 
315
        case CDG_INST_TILE_BLOCK_XOR:
 
316
        case CDG_INST_TILE_BLOCK:
 
317
            if (buf_size - CDG_HEADER_SIZE < CDG_DATA_SIZE) {
 
318
                av_log(avctx, AV_LOG_ERROR, "buffer too small for drawing tile\n");
 
319
                return AVERROR(EINVAL);
 
320
            }
 
321
 
 
322
            ret = cdg_tile_block(cc, cdg_data, inst == CDG_INST_TILE_BLOCK_XOR);
 
323
            if (ret) {
 
324
                av_log(avctx, AV_LOG_ERROR, "tile is out of range\n");
 
325
                return ret;
 
326
            }
 
327
            break;
 
328
        case CDG_INST_SCROLL_PRESET:
 
329
        case CDG_INST_SCROLL_COPY:
 
330
            if (buf_size - CDG_HEADER_SIZE < CDG_MINIMUM_SCROLL_SIZE) {
 
331
                av_log(avctx, AV_LOG_ERROR, "buffer too small for scrolling\n");
 
332
                return AVERROR(EINVAL);
 
333
            }
 
334
 
 
335
            cdg_init_frame(&new_frame);
 
336
            ret = avctx->get_buffer(avctx, &new_frame);
 
337
            if (ret) {
 
338
                av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
 
339
                return ret;
 
340
            }
 
341
 
 
342
            cdg_scroll(cc, cdg_data, &new_frame, inst == CDG_INST_SCROLL_COPY);
 
343
            avctx->release_buffer(avctx, &cc->frame);
 
344
            cc->frame = new_frame;
 
345
            break;
 
346
        default:
 
347
            break;
 
348
        }
 
349
 
 
350
        *data_size = sizeof(AVFrame);
 
351
    } else {
 
352
        *data_size = 0;
 
353
        buf_size   = 0;
 
354
    }
 
355
 
 
356
    *(AVFrame *) data = cc->frame;
 
357
    return buf_size;
 
358
}
 
359
 
 
360
static av_cold int cdg_decode_end(AVCodecContext *avctx)
 
361
{
 
362
    CDGraphicsContext *cc = avctx->priv_data;
 
363
 
 
364
    if (cc->frame.data[0])
 
365
        avctx->release_buffer(avctx, &cc->frame);
 
366
 
 
367
    return 0;
 
368
}
 
369
 
 
370
AVCodec ff_cdgraphics_decoder = {
 
371
    "cdgraphics",
 
372
    AVMEDIA_TYPE_VIDEO,
 
373
    CODEC_ID_CDGRAPHICS,
 
374
    sizeof(CDGraphicsContext),
 
375
    cdg_decode_init,
 
376
    NULL,
 
377
    cdg_decode_end,
 
378
    cdg_decode_frame,
 
379
    CODEC_CAP_DR1,
 
380
    .max_lowres = 5,
 
381
    .long_name = NULL_IF_CONFIG_SMALL("CD Graphics video"),
 
382
};