annotate cdgraphics.c @ 12530:63edd10ad4bc libavcodec tip

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