Libav 0.7.1
|
00001 /* 00002 * QPEG codec 00003 * Copyright (c) 2004 Konstantin Shishkov 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00027 #include "avcodec.h" 00028 00029 typedef struct QpegContext{ 00030 AVCodecContext *avctx; 00031 AVFrame pic; 00032 uint8_t *refdata; 00033 uint32_t pal[256]; 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) /* end-of-picture code */ 00055 break; 00056 if(code >= 0xF8) { /* very long run */ 00057 c0 = *src++; 00058 c1 = *src++; 00059 size -= 2; 00060 run = ((code & 0x7) << 16) + (c0 << 8) + c1 + 2; 00061 } else if (code >= 0xF0) { /* long run */ 00062 c0 = *src++; 00063 size--; 00064 run = ((code & 0xF) << 8) + c0 + 2; 00065 } else if (code >= 0xE0) { /* short run */ 00066 run = (code & 0x1F) + 2; 00067 } else if (code >= 0xC0) { /* very long copy */ 00068 c0 = *src++; 00069 c1 = *src++; 00070 size -= 2; 00071 copy = ((code & 0x3F) << 16) + (c0 << 8) + c1 + 1; 00072 } else if (code >= 0x80) { /* long copy */ 00073 c0 = *src++; 00074 size--; 00075 copy = ((code & 0x7F) << 8) + c0 + 1; 00076 } else { /* short copy */ 00077 copy = code + 1; 00078 } 00079 00080 /* perform actual run or copy */ 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 const int qpeg_table_h[16] = 00113 { 0x00, 0x20, 0x20, 0x20, 0x18, 0x10, 0x10, 0x20, 0x10, 0x08, 0x18, 0x08, 0x08, 0x18, 0x10, 0x04}; 00114 static const int qpeg_table_w[16] = 00115 { 0x00, 0x20, 0x18, 0x08, 0x18, 0x10, 0x20, 0x10, 0x08, 0x10, 0x20, 0x20, 0x08, 0x10, 0x18, 0x04}; 00116 00117 /* Decodes delta frames */ 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 /* copy prev frame */ 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 /* motion compensation */ 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 /* get block size by index */ 00149 me_idx = code & 0xF; 00150 me_w = qpeg_table_w[me_idx]; 00151 me_h = qpeg_table_h[me_idx]; 00152 00153 /* extract motion vector */ 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 /* check motion vector */ 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 /* do motion compensation */ 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) /* end-of-picture code */ 00188 break; 00189 if(code > 0xE0) { /* run code: 0xE1..0xFF */ 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) { /* copy code: 0xC0..0xDF */ 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) { /* skip code: 0x80..0xBF */ 00216 int skip; 00217 00218 code &= 0x3F; 00219 /* codes 0x80 and 0x81 are actually escape codes, 00220 skip value minus constant is in the next byte */ 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 /* zero code treated as one-pixel skip */ 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 AVPacket *avpkt) 00253 { 00254 const uint8_t *buf = avpkt->data; 00255 int buf_size = avpkt->size; 00256 QpegContext * const a = avctx->priv_data; 00257 AVFrame * const p= (AVFrame*)&a->pic; 00258 uint8_t* outdata; 00259 int delta; 00260 const uint8_t *pal = av_packet_get_side_data(avpkt, AV_PKT_DATA_PALETTE, NULL); 00261 00262 p->reference = 3; 00263 if (avctx->reget_buffer(avctx, p) < 0) { 00264 av_log(avctx, AV_LOG_ERROR, "reget_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 /* make the palette available on the way out */ 00276 if (pal) { 00277 a->pic.palette_has_changed = 1; 00278 memcpy(a->pal, pal, AVPALETTE_SIZE); 00279 } 00280 memcpy(a->pic.data[1], a->pal, AVPALETTE_SIZE); 00281 00282 *data_size = sizeof(AVFrame); 00283 *(AVFrame*)data = a->pic; 00284 00285 return buf_size; 00286 } 00287 00288 static av_cold 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->refdata = av_malloc(avctx->width * avctx->height); 00294 00295 return 0; 00296 } 00297 00298 static av_cold int decode_end(AVCodecContext *avctx){ 00299 QpegContext * const a = avctx->priv_data; 00300 AVFrame * const p= (AVFrame*)&a->pic; 00301 00302 if(p->data[0]) 00303 avctx->release_buffer(avctx, p); 00304 00305 av_free(a->refdata); 00306 return 0; 00307 } 00308 00309 AVCodec ff_qpeg_decoder = { 00310 "qpeg", 00311 AVMEDIA_TYPE_VIDEO, 00312 CODEC_ID_QPEG, 00313 sizeof(QpegContext), 00314 decode_init, 00315 NULL, 00316 decode_end, 00317 decode_frame, 00318 CODEC_CAP_DR1, 00319 .long_name = NULL_IF_CONFIG_SMALL("Q-team QPEG"), 00320 };