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