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