00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "avcodec.h"
00027 #include "mpegvideo.h"
00028
00029 typedef struct QpegContext{
00030 AVCodecContext *avctx;
00031 AVFrame pic;
00032 uint8_t *refdata;
00033 } QpegContext;
00034
00035 static void qpeg_decode_intra(uint8_t *src, uint8_t *dst, int size,
00036 int stride, int width, int height)
00037 {
00038 int i;
00039 int code;
00040 int c0, c1;
00041 int run, copy;
00042 int filled = 0;
00043
00044 height--;
00045 dst = dst + height * stride;
00046
00047 while(size > 0) {
00048 code = *src++;
00049 size--;
00050 run = copy = 0;
00051 if(code == 0xFC)
00052 break;
00053 if(code >= 0xF8) {
00054 c0 = *src++;
00055 c1 = *src++;
00056 size -= 2;
00057 run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
00058 } else if (code >= 0xF0) {
00059 c0 = *src++;
00060 size--;
00061 run = ((code & 0xF) << 8) + c0 + 2;
00062 } else if (code >= 0xE0) {
00063 run = (code & 0x1F) + 2;
00064 } else if (code >= 0xC0) {
00065 c0 = *src++;
00066 c1 = *src++;
00067 size -= 2;
00068 copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
00069 } else if (code >= 0x80) {
00070 c0 = *src++;
00071 size--;
00072 copy = ((code & 0x7F) << 8) + c0 + 1;
00073 } else {
00074 copy = code + 1;
00075 }
00076
00077
00078 if(run) {
00079 int p;
00080
00081 p = *src++;
00082 size--;
00083 for(i = 0; i < run; i++) {
00084 dst[filled++] = p;
00085 if (filled >= width) {
00086 filled = 0;
00087 dst -= stride;
00088 }
00089 }
00090 } else {
00091 for(i = 0; i < copy; i++) {
00092 dst[filled++] = *src++;
00093 if (filled >= width) {
00094 filled = 0;
00095 dst -= stride;
00096 }
00097 }
00098 size -= copy;
00099 }
00100 }
00101 }
00102
00103 static int qpeg_table_h[16] =
00104 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
00105 static int qpeg_table_w[16] =
00106 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
00107
00108
00109 static void qpeg_decode_inter(uint8_t *src, uint8_t *dst, int size,
00110 int stride, int width, int height,
00111 int delta, uint8_t *ctable, uint8_t *refdata)
00112 {
00113 int i, j;
00114 int code;
00115 int filled = 0;
00116 uint8_t *blkdata;
00117
00118
00119 for(i = 0; i < height; i++)
00120 memcpy(refdata + (i * width), dst + (i * stride), width);
00121
00122 blkdata = src - 0x86;
00123 height--;
00124 dst = dst + height * stride;
00125
00126 while(size > 0) {
00127 code = *src++;
00128 size--;
00129
00130 if(delta) {
00131
00132 while((code & 0xF0) == 0xF0) {
00133 if(delta == 1) {
00134 int me_idx;
00135 int me_w, me_h, me_x, me_y;
00136 uint8_t *me_plane;
00137 int corr, val;
00138
00139
00140 me_idx = code & 0xF;
00141 me_w = qpeg_table_w[me_idx];
00142 me_h = qpeg_table_h[me_idx];
00143
00144
00145 corr = *src++;
00146 size--;
00147
00148 val = corr >> 4;
00149 if(val > 7)
00150 val -= 16;
00151 me_x = val;
00152
00153 val = corr & 0xF;
00154 if(val > 7)
00155 val -= 16;
00156 me_y = val;
00157
00158
00159 me_plane = refdata + (filled + me_x) + (height - me_y) * width;
00160 for(j = 0; j < me_h; j++) {
00161 for(i = 0; i < me_w; i++)
00162 dst[filled + i - (j * stride)] = me_plane[i - (j * width)];
00163 }
00164 }
00165 code = *src++;
00166 size--;
00167 }
00168 }
00169
00170 if(code == 0xE0)
00171 break;
00172 if(code > 0xE0) {
00173 int p;
00174
00175 code &= 0x1F;
00176 p = *src++;
00177 size--;
00178 for(i = 0; i <= code; i++) {
00179 dst[filled++] = p;
00180 if(filled >= width) {
00181 filled = 0;
00182 dst -= stride;
00183 height--;
00184 }
00185 }
00186 } else if(code >= 0xC0) {
00187 code &= 0x1F;
00188
00189 for(i = 0; i <= code; i++) {
00190 dst[filled++] = *src++;
00191 if(filled >= width) {
00192 filled = 0;
00193 dst -= stride;
00194 height--;
00195 }
00196 }
00197 size -= code + 1;
00198 } else if(code >= 0x80) {
00199 int skip;
00200
00201 code &= 0x3F;
00202
00203
00204 if(!code)
00205 skip = (*src++) + 64;
00206 else if(code == 1)
00207 skip = (*src++) + 320;
00208 else
00209 skip = code;
00210 filled += skip;
00211 while( filled >= width) {
00212 filled -= width;
00213 dst -= stride;
00214 height--;
00215 }
00216 } else {
00217
00218 if(code)
00219 dst[filled++] = ctable[code & 0x7F];
00220 else
00221 filled++;
00222 if(filled >= width) {
00223 filled = 0;
00224 dst -= stride;
00225 height--;
00226 }
00227 }
00228 }
00229 }
00230
00231 static int decode_frame(AVCodecContext *avctx,
00232 void *data, int *data_size,
00233 uint8_t *buf, int buf_size)
00234 {
00235 QpegContext * const a = avctx->priv_data;
00236 AVFrame * const p= (AVFrame*)&a->pic;
00237 uint8_t* outdata;
00238 int delta;
00239
00240 if(p->data[0])
00241 avctx->release_buffer(avctx, p);
00242
00243 p->reference= 0;
00244 if(avctx->get_buffer(avctx, p) < 0){
00245 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00246 return -1;
00247 }
00248 outdata = a->pic.data[0];
00249 if(buf[0x85] == 0x10) {
00250 qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
00251 } else {
00252 delta = buf[0x85];
00253 qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata);
00254 }
00255
00256
00257 memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
00258 if (a->avctx->palctrl->palette_changed) {
00259 a->pic.palette_has_changed = 1;
00260 a->avctx->palctrl->palette_changed = 0;
00261 }
00262
00263 *data_size = sizeof(AVFrame);
00264 *(AVFrame*)data = a->pic;
00265
00266 return buf_size;
00267 }
00268
00269 static int decode_init(AVCodecContext *avctx){
00270 QpegContext * const a = avctx->priv_data;
00271
00272 a->avctx = avctx;
00273 avctx->pix_fmt= PIX_FMT_PAL8;
00274 avctx->has_b_frames = 0;
00275 a->pic.data[0] = NULL;
00276 a->refdata = av_malloc(avctx->width * avctx->height);
00277
00278 return 0;
00279 }
00280
00281 static int decode_end(AVCodecContext *avctx){
00282 QpegContext * const a = avctx->priv_data;
00283 AVFrame * const p= (AVFrame*)&a->pic;
00284
00285 if(p->data[0])
00286 avctx->release_buffer(avctx, p);
00287
00288 av_free(a->refdata);
00289 return 0;
00290 }
00291
00292 AVCodec qpeg_decoder = {
00293 "qpeg",
00294 CODEC_TYPE_VIDEO,
00295 CODEC_ID_QPEG,
00296 sizeof(QpegContext),
00297 decode_init,
00298 NULL,
00299 decode_end,
00300 decode_frame,
00301 CODEC_CAP_DR1,
00302 };