]> git.sesse.net Git - ffmpeg/blob - libavcodec/qpeg.c
fix decoding of (broken) files with f_code=0
[ffmpeg] / libavcodec / qpeg.c
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     if(p->data[0])
241         avctx->release_buffer(avctx, p);
242
243     p->reference= 0;
244     if(avctx->get_buffer(avctx, p) < 0){
245         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
246         return -1;
247     }
248     outdata = a->pic.data[0];
249     if(buf[0x85] == 0x10) {
250         qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
251     } else {
252         delta = buf[0x85];
253         qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata);
254     }
255
256     /* make the palette available on the way out */
257     memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
258     if (a->avctx->palctrl->palette_changed) {
259         a->pic.palette_has_changed = 1;
260         a->avctx->palctrl->palette_changed = 0;
261     }
262
263     *data_size = sizeof(AVFrame);
264     *(AVFrame*)data = a->pic;
265     
266     return buf_size;
267 }
268
269 static int decode_init(AVCodecContext *avctx){
270     QpegContext * const a = avctx->priv_data;
271     
272     a->avctx = avctx;
273     avctx->pix_fmt= PIX_FMT_PAL8;
274     avctx->has_b_frames = 0;
275     a->pic.data[0] = NULL;
276     a->refdata = av_malloc(avctx->width * avctx->height);
277
278     return 0;
279 }
280
281 static int decode_end(AVCodecContext *avctx){
282     QpegContext * const a = avctx->priv_data;
283     AVFrame * const p= (AVFrame*)&a->pic;
284     
285     if(p->data[0])
286         avctx->release_buffer(avctx, p);
287
288     av_free(a->refdata);
289     return 0;
290 }
291
292 AVCodec qpeg_decoder = {
293     "qpeg",
294     CODEC_TYPE_VIDEO,
295     CODEC_ID_QPEG,
296     sizeof(QpegContext),
297     decode_init,
298     NULL,
299     decode_end,
300     decode_frame,
301     CODEC_CAP_DR1,
302 };