Mercurial > libavcodec.hg
comparison qpeg.c @ 2355:69fcdad5f7d5 libavcodec
native QPEG video decoder, courtesy of Konstantin Shishkov
author | melanson |
---|---|
date | Wed, 17 Nov 2004 03:45:53 +0000 |
parents | |
children | f67b63ed036d |
comparison
equal
deleted
inserted
replaced
2354:643724c609ff | 2355:69fcdad5f7d5 |
---|---|
1 /* | |
2 * QPEG codec | |
3 * Copyright (c) 2004 Konstantin Shishkov | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Lesser General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Lesser General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Lesser General Public | |
16 * License along with this library; if not, write to the Free Software | |
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 * | |
19 */ | |
20 | |
21 /** | |
22 * @file qpeg.c | |
23 * QPEG codec. | |
24 */ | |
25 | |
26 #include "avcodec.h" | |
27 #include "mpegvideo.h" | |
28 | |
29 typedef struct QpegContext{ | |
30 AVCodecContext *avctx; | |
31 AVFrame pic; | |
32 uint8_t *refdata; | |
33 } QpegContext; | |
34 | |
35 static void qpeg_decode_intra(uint8_t *src, uint8_t *dst, int size, | |
36 int stride, int width, int height) | |
37 { | |
38 int i; | |
39 int code; | |
40 int c0, c1; | |
41 int run, copy; | |
42 int filled = 0; | |
43 | |
44 height--; | |
45 dst = dst + height * stride; | |
46 | |
47 while(size > 0) { | |
48 code = *src++; | |
49 size--; | |
50 run = copy = 0; | |
51 if(code == 0xFC) /* end-of-picture code */ | |
52 break; | |
53 if(code >= 0xF8) { /* very long run */ | |
54 c0 = *src++; | |
55 c1 = *src++; | |
56 size -= 2; | |
57 run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2; | |
58 } else if (code >= 0xF0) { /* long run */ | |
59 c0 = *src++; | |
60 size--; | |
61 run = ((code & 0xF) << 8) + c0 + 2; | |
62 } else if (code >= 0xE0) { /* short run */ | |
63 run = (code & 0x1F) + 2; | |
64 } else if (code >= 0xC0) { /* very long copy */ | |
65 c0 = *src++; | |
66 c1 = *src++; | |
67 size -= 2; | |
68 copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1; | |
69 } else if (code >= 0x80) { /* long copy */ | |
70 c0 = *src++; | |
71 size--; | |
72 copy = ((code & 0x7F) << 8) + c0 + 1; | |
73 } else { /* short copy */ | |
74 copy = code + 1; | |
75 } | |
76 | |
77 /* perform actual run or copy */ | |
78 if(run) { | |
79 int p; | |
80 | |
81 p = *src++; | |
82 size--; | |
83 for(i = 0; i < run; i++) { | |
84 dst[filled++] = p; | |
85 if (filled >= width) { | |
86 filled = 0; | |
87 dst -= stride; | |
88 } | |
89 } | |
90 } else { | |
91 for(i = 0; i < copy; i++) { | |
92 dst[filled++] = *src++; | |
93 if (filled >= width) { | |
94 filled = 0; | |
95 dst -= stride; | |
96 } | |
97 } | |
98 size -= copy; | |
99 } | |
100 } | |
101 } | |
102 | |
103 static int qpeg_table_h[16] = | |
104 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04}; | |
105 static int qpeg_table_w[16] = | |
106 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04}; | |
107 | |
108 /* Decodes delta frames */ | |
109 static void qpeg_decode_inter(uint8_t *src, uint8_t *dst, int size, | |
110 int stride, int width, int height, | |
111 int delta, uint8_t *ctable, uint8_t *refdata) | |
112 { | |
113 int i, j; | |
114 int code; | |
115 int filled = 0; | |
116 uint8_t *blkdata; | |
117 | |
118 /* copy prev frame */ | |
119 for(i = 0; i < height; i++) | |
120 memcpy(refdata + (i * width), dst + (i * stride), width); | |
121 | |
122 blkdata = src - 0x86; | |
123 height--; | |
124 dst = dst + height * stride; | |
125 | |
126 while(size > 0) { | |
127 code = *src++; | |
128 size--; | |
129 | |
130 if(delta) { | |
131 /* motion compensation */ | |
132 while((code & 0xF0) == 0xF0) { | |
133 if(delta == 1) { | |
134 int me_idx; | |
135 int me_w, me_h, me_x, me_y; | |
136 uint8_t *me_plane; | |
137 int corr, val; | |
138 | |
139 /* get block size by index */ | |
140 me_idx = code & 0xF; | |
141 me_w = qpeg_table_w[me_idx]; | |
142 me_h = qpeg_table_h[me_idx]; | |
143 | |
144 /* extract motion vector */ | |
145 corr = *src++; | |
146 size--; | |
147 | |
148 val = corr >> 4; | |
149 if(val > 7) | |
150 val -= 16; | |
151 me_x = val; | |
152 | |
153 val = corr & 0xF; | |
154 if(val > 7) | |
155 val -= 16; | |
156 me_y = val; | |
157 | |
158 /* do motion compensation */ | |
159 me_plane = refdata + (filled + me_x) + (height - me_y) * width; | |
160 for(j = 0; j < me_h; j++) { | |
161 for(i = 0; i < me_w; i++) | |
162 dst[filled + i - (j * stride)] = me_plane[i - (j * width)]; | |
163 } | |
164 } | |
165 code = *src++; | |
166 size--; | |
167 } | |
168 } | |
169 | |
170 if(code == 0xE0) /* end-of-picture code */ | |
171 break; | |
172 if(code > 0xE0) { /* run code: 0xE1..0xFF */ | |
173 int p; | |
174 | |
175 code &= 0x1F; | |
176 p = *src++; | |
177 size--; | |
178 for(i = 0; i <= code; i++) { | |
179 dst[filled++] = p; | |
180 if(filled >= width) { | |
181 filled = 0; | |
182 dst -= stride; | |
183 height--; | |
184 } | |
185 } | |
186 } else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */ | |
187 code &= 0x1F; | |
188 | |
189 for(i = 0; i <= code; i++) { | |
190 dst[filled++] = *src++; | |
191 if(filled >= width) { | |
192 filled = 0; | |
193 dst -= stride; | |
194 height--; | |
195 } | |
196 } | |
197 size -= code + 1; | |
198 } else if(code >= 0x80) { /* skip code: 0x80..0xBF */ | |
199 int skip; | |
200 | |
201 code &= 0x3F; | |
202 /* codes 0x80 and 0x81 are actually escape codes, | |
203 skip value minus constant is in the next byte */ | |
204 if(!code) | |
205 skip = (*src++) + 64; | |
206 else if(code == 1) | |
207 skip = (*src++) + 320; | |
208 else | |
209 skip = code; | |
210 filled += skip; | |
211 while( filled >= width) { | |
212 filled -= width; | |
213 dst -= stride; | |
214 height--; | |
215 } | |
216 } else { | |
217 /* zero code treated as one-pixel skip */ | |
218 if(code) | |
219 dst[filled++] = ctable[code & 0x7F]; | |
220 else | |
221 filled++; | |
222 if(filled >= width) { | |
223 filled = 0; | |
224 dst -= stride; | |
225 height--; | |
226 } | |
227 } | |
228 } | |
229 } | |
230 | |
231 static int decode_frame(AVCodecContext *avctx, | |
232 void *data, int *data_size, | |
233 uint8_t *buf, int buf_size) | |
234 { | |
235 QpegContext * const a = avctx->priv_data; | |
236 AVFrame * const p= (AVFrame*)&a->pic; | |
237 uint8_t* outdata; | |
238 int delta; | |
239 | |
240 /* special case for last picture */ | |
241 if (buf_size == 0) { | |
242 return 0; | |
243 } | |
244 | |
245 if(p->data[0]) | |
246 avctx->release_buffer(avctx, p); | |
247 | |
248 p->reference= 0; | |
249 if(avctx->get_buffer(avctx, p) < 0){ | |
250 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); | |
251 return -1; | |
252 } | |
253 outdata = a->pic.data[0]; | |
254 if(buf[0x85] == 0x10) { | |
255 qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height); | |
256 } else { | |
257 delta = buf[0x85]; | |
258 qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata); | |
259 } | |
260 | |
261 /* make the palette available on the way out */ | |
262 memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE); | |
263 if (a->avctx->palctrl->palette_changed) { | |
264 a->pic.palette_has_changed = 1; | |
265 a->avctx->palctrl->palette_changed = 0; | |
266 } | |
267 | |
268 *data_size = sizeof(AVFrame); | |
269 *(AVFrame*)data = a->pic; | |
270 | |
271 return buf_size; | |
272 } | |
273 | |
274 static int decode_init(AVCodecContext *avctx){ | |
275 QpegContext * const a = avctx->priv_data; | |
276 | |
277 a->avctx = avctx; | |
278 avctx->pix_fmt= PIX_FMT_PAL8; | |
279 avctx->has_b_frames = 0; | |
280 a->pic.data[0] = NULL; | |
281 a->refdata = av_malloc(avctx->width * avctx->height); | |
282 | |
283 return 0; | |
284 } | |
285 | |
286 static int decode_end(AVCodecContext *avctx){ | |
287 QpegContext * const a = avctx->priv_data; | |
288 | |
289 av_free(a->refdata); | |
290 return 0; | |
291 } | |
292 | |
293 AVCodec qpeg_decoder = { | |
294 "qpeg", | |
295 CODEC_TYPE_VIDEO, | |
296 CODEC_ID_QPEG, | |
297 sizeof(QpegContext), | |
298 decode_init, | |
299 NULL, | |
300 decode_end, | |
301 decode_frame, | |
302 CODEC_CAP_DR1, | |
303 }; |