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