Browse code

native QPEG video decoder, courtesy of Konstantin Shishkov

Originally committed as revision 3688 to svn://svn.ffmpeg.org/ffmpeg/trunk

Mike Melanson authored on 2004/11/17 12:45:53
Showing 7 changed files
... ...
@@ -7,6 +7,7 @@ version <next>
7 7
 - Electronic Arts Multimedia (WVE/UV2/etc.) file demuxer
8 8
 - Miro VideoXL (VIXL) video decoder
9 9
 - H.261 video encoder
10
+- QPEG video decoder
10 11
 
11 12
 version 0.4.9-pre1:
12 13
 
... ...
@@ -769,6 +769,7 @@ following image formats are supported:
769 769
 @item TechSmith Camtasia     @tab     @tab  X @tab fourcc: TSCC
770 770
 @item IBM Ultimotion         @tab     @tab  X @tab fourcc: ULTI
771 771
 @item Miro VideoXL           @tab     @tab  X @tab fourcc: VIXL
772
+@item QPEG                   @tab     @tab  X @tab fourccs: QPEG, Q1.0, Q1.1
772 773
 @end multitable
773 774
 
774 775
 @code{X} means that the encoding (resp. decoding) is supported.
... ...
@@ -21,7 +21,7 @@ OBJS= common.o utils.o mem.o allcodecs.o \
21 21
       msvideo1.o vqavideo.o idcinvideo.o adx.o rational.o faandct.o 8bps.o \
22 22
       smc.o parser.o flicvideo.o truemotion1.o vmdav.o lcl.o qtrle.o g726.o \
23 23
       flac.o vp3dsp.o integer.o snow.o tscc.o sonic.o ulti.o h264idct.o \
24
-      qdrw.o xl.o rangecoder.o png.o pnm.o
24
+      qdrw.o xl.o rangecoder.o png.o pnm.o qpeg.o
25 25
 
26 26
 ifeq ($(AMR_NB),yes)
27 27
 ifeq ($(AMR_NB_FIXED),yes)
... ...
@@ -119,6 +119,7 @@ void avcodec_register_all(void)
119 119
     register_avcodec(&ulti_decoder);
120 120
     register_avcodec(&qdraw_decoder);
121 121
     register_avcodec(&xl_decoder);
122
+    register_avcodec(&qpeg_decoder);
122 123
 #ifdef CONFIG_FAAD
123 124
     register_avcodec(&aac_decoder);
124 125
     register_avcodec(&mpeg4aac_decoder);
... ...
@@ -17,7 +17,7 @@ extern "C" {
17 17
 
18 18
 #define FFMPEG_VERSION_INT     0x000409
19 19
 #define FFMPEG_VERSION         "0.4.9-pre1"
20
-#define LIBAVCODEC_BUILD       4731
20
+#define LIBAVCODEC_BUILD       4732
21 21
 
22 22
 #define LIBAVCODEC_VERSION_INT FFMPEG_VERSION_INT
23 23
 #define LIBAVCODEC_VERSION     FFMPEG_VERSION
... ...
@@ -105,6 +105,7 @@ enum CodecID {
105 105
     CODEC_ID_ULTI,
106 106
     CODEC_ID_QDRAW,
107 107
     CODEC_ID_VIXL,
108
+    CODEC_ID_QPEG,
108 109
 
109 110
     /* various pcm "codecs" */
110 111
     CODEC_ID_PCM_S16LE,
... ...
@@ -1909,6 +1910,7 @@ extern AVCodec tscc_decoder;
1909 1909
 extern AVCodec ulti_decoder;
1910 1910
 extern AVCodec qdraw_decoder;
1911 1911
 extern AVCodec xl_decoder;
1912
+extern AVCodec qpeg_decoder;
1912 1913
 
1913 1914
 /* pcm codecs */
1914 1915
 #define PCM_CODEC(id, name) \
1915 1916
new file mode 100644
... ...
@@ -0,0 +1,303 @@
0
+/*
1
+ * QPEG codec
2
+ * Copyright (c) 2004 Konstantin Shishkov
3
+ *
4
+ * This library is free software; you can redistribute it and/or
5
+ * modify it under the terms of the GNU Lesser General Public
6
+ * License as published by the Free Software Foundation; either
7
+ * version 2 of the License, or (at your option) any later version.
8
+ *
9
+ * This library is distributed in the hope that it will be useful,
10
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12
+ * Lesser General Public License for more details.
13
+ *
14
+ * You should have received a copy of the GNU Lesser General Public
15
+ * License along with this library; if not, write to the Free Software
16
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17
+ *
18
+ */
19
+ 
20
+/**
21
+ * @file qpeg.c
22
+ * QPEG codec.
23
+ */
24
+ 
25
+#include "avcodec.h"
26
+#include "mpegvideo.h"
27
+
28
+typedef struct QpegContext{
29
+    AVCodecContext *avctx;
30
+    AVFrame pic;
31
+    uint8_t *refdata;
32
+} QpegContext;
33
+
34
+static void qpeg_decode_intra(uint8_t *src, uint8_t *dst, int size,
35
+			    int stride, int width, int height)
36
+{
37
+    int i;
38
+    int code;
39
+    int c0, c1;
40
+    int run, copy;
41
+    int filled = 0;
42
+    
43
+    height--;
44
+    dst = dst + height * stride;
45
+    
46
+    while(size > 0) {
47
+	code = *src++;
48
+	size--;
49
+	run = copy = 0;
50
+	if(code == 0xFC) /* end-of-picture code */
51
+	    break;
52
+	if(code >= 0xF8) { /* very long run */
53
+	    c0 = *src++;
54
+	    c1 = *src++;
55
+	    size -= 2;
56
+	    run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
57
+	} else if (code >= 0xF0) { /* long run */
58
+	    c0 = *src++;
59
+	    size--;
60
+	    run = ((code & 0xF) << 8) + c0 + 2;
61
+	} else if (code >= 0xE0) { /* short run */
62
+	    run = (code & 0x1F) + 2;
63
+	} else if (code >= 0xC0) { /* very long copy */
64
+	    c0 = *src++;
65
+	    c1 = *src++;
66
+	    size -= 2;
67
+	    copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
68
+	} else if (code >= 0x80) { /* long copy */
69
+	    c0 = *src++;
70
+	    size--;
71
+	    copy = ((code & 0x7F) << 8) + c0 + 1;
72
+	} else { /* short copy */
73
+	    copy = code + 1;
74
+	}
75
+	
76
+	/* perform actual run or copy */
77
+	if(run) {
78
+	    int p;
79
+	    
80
+	    p = *src++;
81
+	    size--;
82
+	    for(i = 0; i < run; i++) {
83
+		dst[filled++] = p;
84
+		if (filled >= width) {
85
+		    filled = 0;
86
+		    dst -= stride;
87
+		}
88
+	    }
89
+	} else {
90
+	    for(i = 0; i < copy; i++) {
91
+		dst[filled++] = *src++;
92
+		if (filled >= width) {
93
+		    filled = 0;
94
+		    dst -= stride;
95
+		}
96
+	    }
97
+	    size -= copy;
98
+	}
99
+    }
100
+}
101
+
102
+static int qpeg_table_h[16] = 
103
+ { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
104
+static int qpeg_table_w[16] =
105
+ { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
106
+ 
107
+/* Decodes delta frames */
108
+static void qpeg_decode_inter(uint8_t *src, uint8_t *dst, int size,
109
+			    int stride, int width, int height,
110
+			    int delta, uint8_t *ctable, uint8_t *refdata)
111
+{
112
+    int i, j;
113
+    int code;
114
+    int filled = 0;
115
+    uint8_t *blkdata;
116
+    
117
+    /* copy prev frame */
118
+    for(i = 0; i < height; i++)
119
+	memcpy(refdata + (i * width), dst + (i * stride), width);
120
+    
121
+    blkdata = src - 0x86;
122
+    height--;
123
+    dst = dst + height * stride;
124
+
125
+    while(size > 0) {
126
+	code = *src++;
127
+	size--;
128
+	
129
+	if(delta) {
130
+	    /* motion compensation */
131
+	    while((code & 0xF0) == 0xF0) {
132
+		if(delta == 1) {
133
+		    int me_idx;
134
+		    int me_w, me_h, me_x, me_y;
135
+		    uint8_t *me_plane;
136
+		    int corr, val;
137
+		    
138
+		    /* get block size by index */
139
+		    me_idx = code & 0xF;
140
+		    me_w = qpeg_table_w[me_idx];
141
+		    me_h = qpeg_table_h[me_idx];
142
+		    
143
+		    /* extract motion vector */
144
+		    corr = *src++;
145
+		    size--;
146
+
147
+		    val = corr >> 4;
148
+		    if(val > 7)
149
+			val -= 16;
150
+		    me_x = val;
151
+		    
152
+		    val = corr & 0xF;
153
+		    if(val > 7)
154
+			val -= 16;
155
+		    me_y = val;
156
+		    
157
+		    /* do motion compensation */
158
+		    me_plane = refdata + (filled + me_x) + (height - me_y) * width;
159
+		    for(j = 0; j < me_h; j++) {
160
+			for(i = 0; i < me_w; i++)
161
+			    dst[filled + i - (j * stride)] = me_plane[i - (j * width)];
162
+		    }
163
+		}
164
+		code = *src++;
165
+		size--;
166
+	    }
167
+	}
168
+	
169
+	if(code == 0xE0) /* end-of-picture code */
170
+	    break;
171
+	if(code > 0xE0) { /* run code: 0xE1..0xFF */
172
+	    int p;
173
+
174
+	    code &= 0x1F;
175
+	    p = *src++;
176
+	    size--;
177
+	    for(i = 0; i <= code; i++) {
178
+		dst[filled++] = p;
179
+		if(filled >= width) {
180
+		    filled = 0;
181
+		    dst -= stride;
182
+		    height--;
183
+		}
184
+	    }
185
+	} else if(code >= 0xC0) { /* copy code: 0xC0..0xDF */
186
+	    code &= 0x1F;
187
+	    
188
+	    for(i = 0; i <= code; i++) {
189
+		dst[filled++] = *src++;
190
+		if(filled >= width) {
191
+		    filled = 0;
192
+		    dst -= stride;
193
+		    height--;
194
+		}
195
+	    }
196
+	    size -= code + 1;
197
+	} else if(code >= 0x80) { /* skip code: 0x80..0xBF */
198
+	    int skip;
199
+	    
200
+	    code &= 0x3F;
201
+	    /* codes 0x80 and 0x81 are actually escape codes,
202
+	       skip value minus constant is in the next byte */
203
+	    if(!code)
204
+		skip = (*src++) + 64;
205
+	    else if(code == 1)
206
+		skip = (*src++) + 320;
207
+	    else
208
+		skip = code;
209
+	    filled += skip;
210
+	    while( filled >= width) {
211
+		filled -= width;
212
+		dst -= stride;
213
+		height--;
214
+	    }
215
+	} else {
216
+	    /* zero code treated as one-pixel skip */
217
+	    if(code)
218
+		dst[filled++] = ctable[code & 0x7F];
219
+	    else
220
+		filled++;
221
+	    if(filled >= width) {
222
+		filled = 0;
223
+		dst -= stride;
224
+		height--;
225
+	    }
226
+	}
227
+    }
228
+}
229
+
230
+static int decode_frame(AVCodecContext *avctx, 
231
+                        void *data, int *data_size,
232
+                        uint8_t *buf, int buf_size)
233
+{
234
+    QpegContext * const a = avctx->priv_data;
235
+    AVFrame * const p= (AVFrame*)&a->pic;
236
+    uint8_t* outdata;
237
+    int delta;
238
+    
239
+    /* special case for last picture */
240
+    if (buf_size == 0) {
241
+        return 0;
242
+    }
243
+
244
+    if(p->data[0])
245
+        avctx->release_buffer(avctx, p);
246
+
247
+    p->reference= 0;
248
+    if(avctx->get_buffer(avctx, p) < 0){
249
+        av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
250
+        return -1;
251
+    }
252
+    outdata = a->pic.data[0];
253
+    if(buf[0x85] == 0x10) {
254
+	qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
255
+    } else {
256
+	delta = buf[0x85];
257
+	qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata);
258
+    }
259
+
260
+    /* make the palette available on the way out */
261
+    memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
262
+    if (a->avctx->palctrl->palette_changed) {
263
+        a->pic.palette_has_changed = 1;
264
+        a->avctx->palctrl->palette_changed = 0;
265
+    }
266
+
267
+    *data_size = sizeof(AVFrame);
268
+    *(AVFrame*)data = a->pic;
269
+    
270
+    return buf_size;
271
+}
272
+
273
+static int decode_init(AVCodecContext *avctx){
274
+    QpegContext * const a = avctx->priv_data;
275
+    
276
+    a->avctx = avctx;
277
+    avctx->pix_fmt= PIX_FMT_PAL8;
278
+    avctx->has_b_frames = 0;
279
+    a->pic.data[0] = NULL;
280
+    a->refdata = av_malloc(avctx->width * avctx->height);
281
+
282
+    return 0;
283
+}
284
+
285
+static int decode_end(AVCodecContext *avctx){
286
+    QpegContext * const a = avctx->priv_data;
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
+};
... ...
@@ -170,6 +170,9 @@ const CodecTag codec_bmp_tags[] = {
170 170
     { CODEC_ID_TSCC, MKTAG('t', 's', 'c', 'c') },
171 171
     { CODEC_ID_ULTI, MKTAG('U', 'L', 'T', 'I') },
172 172
     { CODEC_ID_VIXL, MKTAG('V', 'I', 'X', 'L') },
173
+    { CODEC_ID_QPEG, MKTAG('Q', 'P', 'E', 'G') },
174
+    { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '0') },
175
+    { CODEC_ID_QPEG, MKTAG('Q', '1', '.', '1') },
173 176
     { CODEC_ID_RAWVIDEO, 0 },
174 177
     { 0, 0 },
175 178
 };