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 AVPacket *avpkt)
00252 {
00253 const uint8_t *buf = avpkt->data;
00254 int buf_size = avpkt->size;
00255 QpegContext * const a = avctx->priv_data;
00256 AVFrame * const p= (AVFrame*)&a->pic;
00257 uint8_t* outdata;
00258 int delta;
00259
00260 if(p->data[0])
00261 avctx->release_buffer(avctx, p);
00262
00263 p->reference= 0;
00264 if(avctx->get_buffer(avctx, p) < 0){
00265 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00266 return -1;
00267 }
00268 outdata = a->pic.data[0];
00269 if(buf[0x85] == 0x10) {
00270 qpeg_decode_intra(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height);
00271 } else {
00272 delta = buf[0x85];
00273 qpeg_decode_inter(buf+0x86, outdata, buf_size - 0x86, a->pic.linesize[0], avctx->width, avctx->height, delta, buf + 4, a->refdata);
00274 }
00275
00276
00277 memcpy(a->pic.data[1], a->avctx->palctrl->palette, AVPALETTE_SIZE);
00278 if (a->avctx->palctrl->palette_changed) {
00279 a->pic.palette_has_changed = 1;
00280 a->avctx->palctrl->palette_changed = 0;
00281 }
00282
00283 *data_size = sizeof(AVFrame);
00284 *(AVFrame*)data = a->pic;
00285
00286 return buf_size;
00287 }
00288
00289 static av_cold int decode_init(AVCodecContext *avctx){
00290 QpegContext * const a = avctx->priv_data;
00291
00292 if (!avctx->palctrl) {
00293 av_log(avctx, AV_LOG_FATAL, "Missing required palette via palctrl\n");
00294 return -1;
00295 }
00296 a->avctx = avctx;
00297 avctx->pix_fmt= PIX_FMT_PAL8;
00298 a->refdata = av_malloc(avctx->width * avctx->height);
00299
00300 return 0;
00301 }
00302
00303 static av_cold int decode_end(AVCodecContext *avctx){
00304 QpegContext * const a = avctx->priv_data;
00305 AVFrame * const p= (AVFrame*)&a->pic;
00306
00307 if(p->data[0])
00308 avctx->release_buffer(avctx, p);
00309
00310 av_free(a->refdata);
00311 return 0;
00312 }
00313
00314 AVCodec qpeg_decoder = {
00315 "qpeg",
00316 AVMEDIA_TYPE_VIDEO,
00317 CODEC_ID_QPEG,
00318 sizeof(QpegContext),
00319 decode_init,
00320 NULL,
00321 decode_end,
00322 decode_frame,
00323 CODEC_CAP_DR1,
00324 .long_name = NULL_IF_CONFIG_SMALL("Q-team QPEG"),
00325 };