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 #include "bytestream.h"
00029
00030 typedef struct QpegContext{
00031 AVCodecContext *avctx;
00032 AVFrame pic, ref;
00033 uint32_t pal[256];
00034 GetByteContext buffer;
00035 } QpegContext;
00036
00037 static void qpeg_decode_intra(QpegContext *qctx, uint8_t *dst,
00038 int stride, int width, int height)
00039 {
00040 int i;
00041 int code;
00042 int c0, c1;
00043 int run, copy;
00044 int filled = 0;
00045 int rows_to_go;
00046
00047 rows_to_go = height;
00048 height--;
00049 dst = dst + height * stride;
00050
00051 while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (rows_to_go > 0)) {
00052 code = bytestream2_get_byte(&qctx->buffer);
00053 run = copy = 0;
00054 if(code == 0xFC)
00055 break;
00056 if(code >= 0xF8) {
00057 c0 = bytestream2_get_byte(&qctx->buffer);
00058 c1 = bytestream2_get_byte(&qctx->buffer);
00059 run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2;
00060 } else if (code >= 0xF0) {
00061 c0 = bytestream2_get_byte(&qctx->buffer);
00062 run = ((code & 0xF) << 8) + c0 + 2;
00063 } else if (code >= 0xE0) {
00064 run = (code & 0x1F) + 2;
00065 } else if (code >= 0xC0) {
00066 c0 = bytestream2_get_byte(&qctx->buffer);
00067 c1 = bytestream2_get_byte(&qctx->buffer);
00068 copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1;
00069 } else if (code >= 0x80) {
00070 c0 = bytestream2_get_byte(&qctx->buffer);
00071 copy = ((code & 0x7F) << 8) + c0 + 1;
00072 } else {
00073 copy = code + 1;
00074 }
00075
00076
00077 if(run) {
00078 int p;
00079
00080 p = bytestream2_get_byte(&qctx->buffer);
00081 for(i = 0; i < run; i++) {
00082 dst[filled++] = p;
00083 if (filled >= width) {
00084 filled = 0;
00085 dst -= stride;
00086 rows_to_go--;
00087 if(rows_to_go <= 0)
00088 break;
00089 }
00090 }
00091 } else {
00092 for(i = 0; i < copy; i++) {
00093 dst[filled++] = bytestream2_get_byte(&qctx->buffer);
00094 if (filled >= width) {
00095 filled = 0;
00096 dst -= stride;
00097 rows_to_go--;
00098 if(rows_to_go <= 0)
00099 break;
00100 }
00101 }
00102 }
00103 }
00104 }
00105
00106 static const int qpeg_table_h[16] =
00107 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04};
00108 static const int qpeg_table_w[16] =
00109 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04};
00110
00111
00112 static void qpeg_decode_inter(QpegContext *qctx, uint8_t *dst,
00113 int stride, int width, int height,
00114 int delta, const uint8_t *ctable,
00115 uint8_t *refdata)
00116 {
00117 int i, j;
00118 int code;
00119 int filled = 0;
00120 int orig_height;
00121
00122 if(!refdata)
00123 refdata= dst;
00124
00125
00126 for(i = 0; i < height; i++)
00127 memcpy(dst + (i * stride), refdata + (i * stride), width);
00128
00129 orig_height = height;
00130 height--;
00131 dst = dst + height * stride;
00132
00133 while ((bytestream2_get_bytes_left(&qctx->buffer) > 0) && (height >= 0)) {
00134 code = bytestream2_get_byte(&qctx->buffer);
00135
00136 if(delta) {
00137
00138 while(bytestream2_get_bytes_left(&qctx->buffer) > 0 && (code & 0xF0) == 0xF0) {
00139 if(delta == 1) {
00140 int me_idx;
00141 int me_w, me_h, me_x, me_y;
00142 uint8_t *me_plane;
00143 int corr, val;
00144
00145
00146 me_idx = code & 0xF;
00147 me_w = qpeg_table_w[me_idx];
00148 me_h = qpeg_table_h[me_idx];
00149
00150
00151 corr = bytestream2_get_byte(&qctx->buffer);
00152
00153 val = corr >> 4;
00154 if(val > 7)
00155 val -= 16;
00156 me_x = val;
00157
00158 val = corr & 0xF;
00159 if(val > 7)
00160 val -= 16;
00161 me_y = val;
00162
00163
00164 if ((me_x + filled < 0) || (me_x + me_w + filled > width) ||
00165 (height - me_y - me_h < 0) || (height - me_y > orig_height) ||
00166 (filled + me_w > width) || (height - me_h < 0))
00167 av_log(NULL, AV_LOG_ERROR, "Bogus motion vector (%i,%i), block size %ix%i at %i,%i\n",
00168 me_x, me_y, me_w, me_h, filled, height);
00169 else {
00170
00171 me_plane = refdata + (filled + me_x) + (height - me_y) * stride;
00172 for(j = 0; j < me_h; j++) {
00173 for(i = 0; i < me_w; i++)
00174 dst[filled + i - (j * stride)] = me_plane[i - (j * stride)];
00175 }
00176 }
00177 }
00178 code = bytestream2_get_byte(&qctx->buffer);
00179 }
00180 }
00181
00182 if(code == 0xE0)
00183 break;
00184 if(code > 0xE0) {
00185 int p;
00186
00187 code &= 0x1F;
00188 p = bytestream2_get_byte(&qctx->buffer);
00189 for(i = 0; i <= code; i++) {
00190 dst[filled++] = p;
00191 if(filled >= width) {
00192 filled = 0;
00193 dst -= stride;
00194 height--;
00195 if(height < 0)
00196 break;
00197 }
00198 }
00199 } else if(code >= 0xC0) {
00200 code &= 0x1F;
00201
00202 if(code + 1 > bytestream2_get_bytes_left(&qctx->buffer))
00203 break;
00204
00205 for(i = 0; i <= code; i++) {
00206 dst[filled++] = bytestream2_get_byte(&qctx->buffer);
00207 if(filled >= width) {
00208 filled = 0;
00209 dst -= stride;
00210 height--;
00211 if(height < 0)
00212 break;
00213 }
00214 }
00215 } else if(code >= 0x80) {
00216 int skip;
00217
00218 code &= 0x3F;
00219
00220
00221 if(!code)
00222 skip = bytestream2_get_byte(&qctx->buffer) + 64;
00223 else if(code == 1)
00224 skip = bytestream2_get_byte(&qctx->buffer) + 320;
00225 else
00226 skip = code;
00227 filled += skip;
00228 while( filled >= width) {
00229 filled -= width;
00230 dst -= stride;
00231 height--;
00232 if(height < 0)
00233 break;
00234 }
00235 } else {
00236
00237 if(code) {
00238 dst[filled++] = ctable[code & 0x7F];
00239 }
00240 else
00241 filled++;
00242 if(filled >= width) {
00243 filled = 0;
00244 dst -= stride;
00245 height--;
00246 }
00247 }
00248 }
00249 }
00250
00251 static int decode_frame(AVCodecContext *avctx,
00252 void *data, int *data_size,
00253 AVPacket *avpkt)
00254 {
00255 uint8_t ctable[128];
00256 QpegContext * const a = avctx->priv_data;
00257 AVFrame * p = &a->pic;
00258 AVFrame * ref= &a->ref;
00259 uint8_t* outdata;
00260 int delta;
00261 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL);
00262
00263 if (avpkt->size < 0x86) {
00264 av_log(avctx, AV_LOG_ERROR, "Packet is too small\n");
00265 return AVERROR_INVALIDDATA;
00266 }
00267
00268 bytestream2_init(&a->buffer, avpkt->data, avpkt->size);
00269
00270 if(ref->data[0])
00271 avctx->release_buffer(avctx, ref);
00272 FFSWAP(AVFrame, *ref, *p);
00273
00274 p->reference= 3;
00275 if(avctx->get_buffer(avctx, p) < 0){
00276 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00277 return -1;
00278 }
00279 outdata = a->pic.data[0];
00280 bytestream2_skip(&a->buffer, 4);
00281 bytestream2_get_buffer(&a->buffer, ctable, 128);
00282 bytestream2_skip(&a->buffer, 1);
00283
00284 delta = bytestream2_get_byte(&a->buffer);
00285 if(delta == 0x10) {
00286 qpeg_decode_intra(a, outdata, a->pic.linesize[0], avctx->width, avctx->height);
00287 } else {
00288 qpeg_decode_inter(a, outdata, a->pic.linesize[0], avctx->width, avctx->height, delta, ctable, a->ref.data[0]);
00289 }
00290
00291
00292 if (pal) {
00293 a->pic.palette_has_changed = 1;
00294 memcpy(a->pal, pal, AVPALETTE_SIZE);
00295 }
00296 memcpy(a->pic.data[1], a->pal, AVPALETTE_SIZE);
00297
00298 *data_size = sizeof(AVFrame);
00299 *(AVFrame*)data = a->pic;
00300
00301 return avpkt->size;
00302 }
00303
00304 static av_cold int decode_init(AVCodecContext *avctx){
00305 QpegContext * const a = avctx->priv_data;
00306
00307 avcodec_get_frame_defaults(&a->pic);
00308 avcodec_get_frame_defaults(&a->ref);
00309 a->avctx = avctx;
00310 avctx->pix_fmt= PIX_FMT_PAL8;
00311
00312 return 0;
00313 }
00314
00315 static av_cold int decode_end(AVCodecContext *avctx){
00316 QpegContext * const a = avctx->priv_data;
00317 AVFrame * const p = &a->pic;
00318 AVFrame * const ref= &a->ref;
00319
00320 if(p->data[0])
00321 avctx->release_buffer(avctx, p);
00322 if(ref->data[0])
00323 avctx->release_buffer(avctx, ref);
00324
00325 return 0;
00326 }
00327
00328 AVCodec ff_qpeg_decoder = {
00329 .name = "qpeg",
00330 .type = AVMEDIA_TYPE_VIDEO,
00331 .id = AV_CODEC_ID_QPEG,
00332 .priv_data_size = sizeof(QpegContext),
00333 .init = decode_init,
00334 .close = decode_end,
00335 .decode = decode_frame,
00336 .capabilities = CODEC_CAP_DR1,
00337 .long_name = NULL_IF_CONFIG_SMALL("Q-team QPEG"),
00338 };