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, ref;
00032 uint32_t pal[256];
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 if(!refdata)
00127 refdata= dst;
00128
00129
00130 for(i = 0; i < height; i++)
00131 memcpy(dst + (i * stride), refdata + (i * stride), width);
00132
00133 orig_height = height;
00134 height--;
00135 dst = dst + height * stride;
00136
00137 while((size > 0) && (height >= 0)) {
00138 code = *src++;
00139 size--;
00140
00141 if(delta) {
00142
00143 while((code & 0xF0) == 0xF0) {
00144 if(delta == 1) {
00145 int me_idx;
00146 int me_w, me_h, me_x, me_y;
00147 uint8_t *me_plane;
00148 int corr, val;
00149
00150
00151 me_idx = code & 0xF;
00152 me_w = qpeg_table_w[me_idx];
00153 me_h = qpeg_table_h[me_idx];
00154
00155
00156 corr = *src++;
00157 size--;
00158
00159 val = corr >> 4;
00160 if(val > 7)
00161 val -= 16;
00162 me_x = val;
00163
00164 val = corr & 0xF;
00165 if(val > 7)
00166 val -= 16;
00167 me_y = val;
00168
00169
00170 if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
00171 (height - me_y - me_h < 0) || (height - me_y > orig_height) ||
00172 (filled + me_w > width) || (height - me_h < 0))
00173 av_log(NULL, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
00174 me_x, me_y, me_w, me_h, filled, height);
00175 else {
00176
00177 me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
00178 for(j = 0; j < me_h; j++) {
00179 for(i = 0; i < me_w; i++)
00180 dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
00181 }
00182 }
00183 }
00184 code = *src++;
00185 size--;
00186 }
00187 }
00188
00189 if(code == 0xE0)
00190 break;
00191 if(code > 0xE0) {
00192 int p;
00193
00194 code &= 0x1F;
00195 p = *src++;
00196 size--;
00197 for(i = 0; i <= code; i++) {
00198 dst[filled++] = p;
00199 if(filled >= width) {
00200 filled = 0;
00201 dst -= stride;
00202 height--;
00203 }
00204 }
00205 } else if(code >= 0xC0) {
00206 code &= 0x1F;
00207
00208 for(i = 0; i <= code; i++) {
00209 dst[filled++] = *src++;
00210 if(filled >= width) {
00211 filled = 0;
00212 dst -= stride;
00213 height--;
00214 }
00215 }
00216 size -= code + 1;
00217 } else if(code >= 0x80) {
00218 int skip;
00219
00220 code &= 0x3F;
00221
00222
00223 if(!code)
00224 skip = (*src++) + 64;
00225 else if(code == 1)
00226 skip = (*src++) + 320;
00227 else
00228 skip = code;
00229 filled += skip;
00230 while( filled >= width) {
00231 filled -= width;
00232 dst -= stride;
00233 height--;
00234 if(height < 0)
00235 break;
00236 }
00237 } else {
00238
00239 if(code)
00240 dst[filled++] = ctable[code & 0x7F];
00241 else
00242 filled++;
00243 if(filled >= width) {
00244 filled = 0;
00245 dst -= stride;
00246 height--;
00247 }
00248 }
00249 }
00250 }
00251
00252 static int decode_frame(AVCodecContext *avctx,
00253 void *data, int *data_size,
00254 AVPacket *avpkt)
00255 {
00256 const uint8_t *buf = avpkt->data;
00257 int buf_size = avpkt->size;
00258 QpegContext * const a = avctx->priv_data;
00259 AVFrame * p= (AVFrame*)&a->pic;
00260 AVFrame * ref= (AVFrame*)&a->ref;
00261 uint8_t* outdata;
00262 int delta;
00263
00264 if(ref->data[0])
00265 avctx->release_buffer(avctx, ref);
00266 FFSWAP(AVFrame, *ref, *p);
00267
00268 p->reference= 3;
00269 if(avctx->get_buffer(avctx, p) < 0){
00270 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00271 return -1;
00272 }
00273 outdata = a->pic.data[0];
00274 if(buf[0x85] == 0x10) {
00275 qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
00276 } else {
00277 delta = buf[0x85];
00278 qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->ref.data[0]);
00279 }
00280
00281
00282 memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
00283 if (a->avctx->palctrl->palette_changed) {
00284 a->pic.palette_has_changed = 1;
00285 a->avctx->palctrl->palette_changed = 0;
00286 }
00287
00288 *data_size = sizeof(AVFrame);
00289 *(AVFrame*)data = a->pic;
00290
00291 return buf_size;
00292 }
00293
00294 static av_cold int decode_init(AVCodecContext *avctx){
00295 QpegContext * const a = avctx->priv_data;
00296
00297 if (!avctx->palctrl) {
00298 av_log(avctx, AV_LOG_FATAL, "Missing required palette via palctrl\n");
00299 return -1;
00300 }
00301 avcodec_get_frame_defaults(&a->pic);
00302 avcodec_get_frame_defaults(&a->ref);
00303 a->avctx = avctx;
00304 avctx->pix_fmt= PIX_FMT_PAL8;
00305
00306 return 0;
00307 }
00308
00309 static av_cold int decode_end(AVCodecContext *avctx){
00310 QpegContext * const a = avctx->priv_data;
00311 AVFrame * const p= (AVFrame*)&a->pic;
00312 AVFrame * const ref= (AVFrame*)&a->ref;
00313
00314 if(p->data[0])
00315 avctx->release_buffer(avctx, p);
00316 if(ref->data[0])
00317 avctx->release_buffer(avctx, ref);
00318
00319 return 0;
00320 }
00321
00322 AVCodec ff_qpeg_decoder = {
00323 "qpeg",
00324 AVMEDIA_TYPE_VIDEO,
00325 CODEC_ID_QPEG,
00326 sizeof(QpegContext),
00327 decode_init,
00328 NULL,
00329 decode_end,
00330 decode_frame,
00331 CODEC_CAP_DR1,
00332 .long_name = NULL_IF_CONFIG_SMALL("Q-team QPEG"),
00333 };