1
by Sérgio Benjamim
FFmpeg 2.7.1 source for ppsspp. |
1 |
/*
|
2 |
* Deluxe Paint Animation decoder
|
|
3 |
* Copyright (c) 2009 Peter Ross
|
|
4 |
*
|
|
5 |
* This file is part of FFmpeg.
|
|
6 |
*
|
|
7 |
* FFmpeg 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 |
* FFmpeg 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 FFmpeg; if not, write to the Free Software
|
|
19 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
20 |
*/
|
|
21 |
||
22 |
/**
|
|
23 |
* @file
|
|
24 |
* Deluxe Paint Animation decoder
|
|
25 |
*/
|
|
26 |
||
27 |
#include "avcodec.h" |
|
28 |
#include "bytestream.h" |
|
29 |
#include "internal.h" |
|
30 |
||
31 |
typedef struct AnmContext { |
|
32 |
AVFrame *frame; |
|
33 |
int palette[AVPALETTE_COUNT]; |
|
34 |
GetByteContext gb; |
|
35 |
int x; ///< x coordinate position |
|
36 |
} AnmContext; |
|
37 |
||
38 |
static av_cold int decode_init(AVCodecContext *avctx) |
|
39 |
{
|
|
40 |
AnmContext *s = avctx->priv_data; |
|
41 |
int i; |
|
42 |
||
43 |
avctx->pix_fmt = AV_PIX_FMT_PAL8; |
|
44 |
||
45 |
s->frame = av_frame_alloc(); |
|
46 |
if (!s->frame) |
|
47 |
return AVERROR(ENOMEM); |
|
48 |
||
49 |
bytestream2_init(&s->gb, avctx->extradata, avctx->extradata_size); |
|
50 |
if (bytestream2_get_bytes_left(&s->gb) < 16 * 8 + 4 * 256) { |
|
51 |
av_frame_free(&s->frame); |
|
52 |
return AVERROR_INVALIDDATA; |
|
53 |
}
|
|
54 |
||
55 |
bytestream2_skipu(&s->gb, 16 * 8); |
|
56 |
for (i = 0; i < 256; i++) |
|
57 |
s->palette[i] = bytestream2_get_le32u(&s->gb); |
|
58 |
||
59 |
return 0; |
|
60 |
}
|
|
61 |
||
62 |
/**
|
|
63 |
* Perform decode operation
|
|
64 |
* @param dst pointer to destination image buffer
|
|
65 |
* @param dst_end pointer to end of destination image buffer
|
|
66 |
* @param gb GetByteContext (optional, see below)
|
|
67 |
* @param pixel Fill color (optional, see below)
|
|
68 |
* @param count Pixel count
|
|
69 |
* @param x Pointer to x-axis counter
|
|
70 |
* @param width Image width
|
|
71 |
* @param linesize Destination image buffer linesize
|
|
72 |
* @return non-zero if destination buffer is exhausted
|
|
73 |
*
|
|
74 |
* a copy operation is achieved when 'gb' is set
|
|
75 |
* a fill operation is achieved when 'gb' is null and pixel is >= 0
|
|
76 |
* a skip operation is achieved when 'gb' is null and pixel is < 0
|
|
77 |
*/
|
|
78 |
static inline int op(uint8_t **dst, const uint8_t *dst_end, |
|
79 |
GetByteContext *gb, |
|
80 |
int pixel, int count, |
|
81 |
int *x, int width, int linesize) |
|
82 |
{
|
|
83 |
int remaining = width - *x; |
|
84 |
while(count > 0) { |
|
85 |
int striplen = FFMIN(count, remaining); |
|
86 |
if (gb) { |
|
87 |
if (bytestream2_get_bytes_left(gb) < striplen) |
|
88 |
goto exhausted; |
|
89 |
bytestream2_get_bufferu(gb, *dst, striplen); |
|
90 |
} else if (pixel >= 0) |
|
91 |
memset(*dst, pixel, striplen); |
|
92 |
*dst += striplen; |
|
93 |
remaining -= striplen; |
|
94 |
count -= striplen; |
|
95 |
if (remaining <= 0) { |
|
96 |
*dst += linesize - width; |
|
97 |
remaining = width; |
|
98 |
}
|
|
99 |
if (linesize > 0) { |
|
100 |
if (*dst >= dst_end) goto exhausted; |
|
101 |
} else { |
|
102 |
if (*dst <= dst_end) goto exhausted; |
|
103 |
}
|
|
104 |
}
|
|
105 |
*x = width - remaining; |
|
106 |
return 0; |
|
107 |
||
108 |
exhausted: |
|
109 |
*x = width - remaining; |
|
110 |
return 1; |
|
111 |
}
|
|
112 |
||
113 |
static int decode_frame(AVCodecContext *avctx, |
|
114 |
void *data, int *got_frame, |
|
115 |
AVPacket *avpkt) |
|
116 |
{
|
|
117 |
AnmContext *s = avctx->priv_data; |
|
118 |
const int buf_size = avpkt->size; |
|
119 |
uint8_t *dst, *dst_end; |
|
120 |
int count, ret; |
|
121 |
||
122 |
if ((ret = ff_reget_buffer(avctx, s->frame)) < 0) |
|
123 |
return ret; |
|
124 |
dst = s->frame->data[0]; |
|
125 |
dst_end = s->frame->data[0] + s->frame->linesize[0]*avctx->height; |
|
126 |
||
127 |
bytestream2_init(&s->gb, avpkt->data, buf_size); |
|
128 |
||
129 |
if (bytestream2_get_byte(&s->gb) != 0x42) { |
|
130 |
avpriv_request_sample(avctx, "Unknown record type"); |
|
131 |
return AVERROR_INVALIDDATA; |
|
132 |
}
|
|
133 |
if (bytestream2_get_byte(&s->gb)) { |
|
134 |
avpriv_request_sample(avctx, "Padding bytes"); |
|
135 |
return AVERROR_PATCHWELCOME; |
|
136 |
}
|
|
137 |
bytestream2_skip(&s->gb, 2); |
|
138 |
||
139 |
s->x = 0; |
|
140 |
do { |
|
141 |
/* if statements are ordered by probability */
|
|
142 |
#define OP(gb, pixel, count) \
|
|
143 |
op(&dst, dst_end, (gb), (pixel), (count), &s->x, avctx->width, s->frame->linesize[0])
|
|
144 |
||
145 |
int type = bytestream2_get_byte(&s->gb); |
|
146 |
count = type & 0x7F; |
|
147 |
type >>= 7; |
|
148 |
if (count) { |
|
149 |
if (OP(type ? NULL : &s->gb, -1, count)) break; |
|
150 |
} else if (!type) { |
|
151 |
int pixel; |
|
152 |
count = bytestream2_get_byte(&s->gb); /* count==0 gives nop */ |
|
153 |
pixel = bytestream2_get_byte(&s->gb); |
|
154 |
if (OP(NULL, pixel, count)) break; |
|
155 |
} else { |
|
156 |
int pixel; |
|
157 |
type = bytestream2_get_le16(&s->gb); |
|
158 |
count = type & 0x3FFF; |
|
159 |
type >>= 14; |
|
160 |
if (!count) { |
|
161 |
if (type == 0) |
|
162 |
break; // stop |
|
163 |
if (type == 2) { |
|
164 |
avpriv_request_sample(avctx, "Unknown opcode"); |
|
165 |
return AVERROR_PATCHWELCOME; |
|
166 |
}
|
|
167 |
continue; |
|
168 |
}
|
|
169 |
pixel = type == 3 ? bytestream2_get_byte(&s->gb) : -1; |
|
170 |
if (type == 1) count += 0x4000; |
|
171 |
if (OP(type == 2 ? &s->gb : NULL, pixel, count)) break; |
|
172 |
}
|
|
173 |
} while (bytestream2_get_bytes_left(&s->gb) > 0); |
|
174 |
||
175 |
memcpy(s->frame->data[1], s->palette, AVPALETTE_SIZE); |
|
176 |
||
177 |
*got_frame = 1; |
|
178 |
if ((ret = av_frame_ref(data, s->frame)) < 0) |
|
179 |
return ret; |
|
180 |
||
181 |
return buf_size; |
|
182 |
}
|
|
183 |
||
184 |
static av_cold int decode_end(AVCodecContext *avctx) |
|
185 |
{
|
|
186 |
AnmContext *s = avctx->priv_data; |
|
187 |
||
188 |
av_frame_free(&s->frame); |
|
189 |
return 0; |
|
190 |
}
|
|
191 |
||
192 |
AVCodec ff_anm_decoder = { |
|
193 |
.name = "anm", |
|
194 |
.long_name = NULL_IF_CONFIG_SMALL("Deluxe Paint Animation"), |
|
195 |
.type = AVMEDIA_TYPE_VIDEO, |
|
196 |
.id = AV_CODEC_ID_ANM, |
|
197 |
.priv_data_size = sizeof(AnmContext), |
|
198 |
.init = decode_init, |
|
199 |
.close = decode_end, |
|
200 |
.decode = decode_frame, |
|
201 |
.capabilities = CODEC_CAP_DR1, |
|
202 |
};
|