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