Libav
|
00001 /* 00002 * Electronic Arts TGQ Video Decoder 00003 * Copyright (c) 2007-2008 Peter Ross <pross@xvid.org> 00004 * 00005 * This file is part of FFmpeg. 00006 * 00007 * FFmpeg 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 * FFmpeg 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 FFmpeg; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00020 */ 00021 00031 #include "avcodec.h" 00032 #define ALT_BITSTREAM_READER_LE 00033 #include "get_bits.h" 00034 #include "bytestream.h" 00035 #include "dsputil.h" 00036 #include "aandcttab.h" 00037 00038 typedef struct TgqContext { 00039 AVCodecContext *avctx; 00040 DSPContext dsp; 00041 AVFrame frame; 00042 int width,height; 00043 ScanTable scantable; 00044 int qtable[64]; 00045 DECLARE_ALIGNED(16, DCTELEM, block)[6][64]; 00046 } TgqContext; 00047 00048 static av_cold int tgq_decode_init(AVCodecContext *avctx){ 00049 TgqContext *s = avctx->priv_data; 00050 s->avctx = avctx; 00051 if(avctx->idct_algo==FF_IDCT_AUTO) 00052 avctx->idct_algo=FF_IDCT_EA; 00053 dsputil_init(&s->dsp, avctx); 00054 ff_init_scantable(s->dsp.idct_permutation, &s->scantable, ff_zigzag_direct); 00055 avctx->time_base = (AVRational){1, 15}; 00056 avctx->pix_fmt = PIX_FMT_YUV420P; 00057 return 0; 00058 } 00059 00060 static void tgq_decode_block(TgqContext *s, DCTELEM block[64], GetBitContext *gb){ 00061 uint8_t *perm = s->scantable.permutated; 00062 int i,j,value; 00063 block[0] = get_sbits(gb,8) * s->qtable[0]; 00064 for(i=1; i<64; ) { 00065 switch(show_bits(gb,3)) { 00066 case 4: 00067 block[perm[i++]] = 0; 00068 case 0: 00069 block[perm[i++]] = 0; 00070 skip_bits(gb,3); 00071 break; 00072 case 5: 00073 case 1: 00074 skip_bits(gb,2); 00075 value = get_bits(gb,6); 00076 for(j=0; j<value; j++) 00077 block[perm[i++]] = 0; 00078 break; 00079 case 6: 00080 skip_bits(gb,3); 00081 block[perm[i]] = -s->qtable[perm[i]]; 00082 i++; 00083 break; 00084 case 2: 00085 skip_bits(gb,3); 00086 block[perm[i]] = s->qtable[perm[i]]; 00087 i++; 00088 break; 00089 case 7: // 111b 00090 case 3: // 011b 00091 skip_bits(gb,2); 00092 if (show_bits(gb,6)==0x3F) { 00093 skip_bits(gb, 6); 00094 block[perm[i]] = get_sbits(gb,8)*s->qtable[perm[i]]; 00095 }else{ 00096 block[perm[i]] = get_sbits(gb,6)*s->qtable[perm[i]]; 00097 } 00098 i++; 00099 break; 00100 } 00101 } 00102 block[0] += 128<<4; 00103 } 00104 00105 static void tgq_idct_put_mb(TgqContext *s, DCTELEM (*block)[64], int mb_x, int mb_y){ 00106 int linesize= s->frame.linesize[0]; 00107 uint8_t *dest_y = s->frame.data[0] + (mb_y * 16* linesize ) + mb_x * 16; 00108 uint8_t *dest_cb = s->frame.data[1] + (mb_y * 8 * s->frame.linesize[1]) + mb_x * 8; 00109 uint8_t *dest_cr = s->frame.data[2] + (mb_y * 8 * s->frame.linesize[2]) + mb_x * 8; 00110 00111 s->dsp.idct_put(dest_y , linesize, block[0]); 00112 s->dsp.idct_put(dest_y + 8, linesize, block[1]); 00113 s->dsp.idct_put(dest_y + 8*linesize , linesize, block[2]); 00114 s->dsp.idct_put(dest_y + 8*linesize + 8, linesize, block[3]); 00115 if(!(s->avctx->flags&CODEC_FLAG_GRAY)){ 00116 s->dsp.idct_put(dest_cb, s->frame.linesize[1], block[4]); 00117 s->dsp.idct_put(dest_cr, s->frame.linesize[2], block[5]); 00118 } 00119 } 00120 00121 static inline void tgq_dconly(TgqContext *s, unsigned char *dst, int dst_stride, int dc){ 00122 int level = av_clip_uint8((dc*s->qtable[0] + 2056)>>4); 00123 int j; 00124 for(j=0;j<8;j++) 00125 memset(dst+j*dst_stride, level, 8); 00126 } 00127 00128 static void tgq_idct_put_mb_dconly(TgqContext *s, int mb_x, int mb_y, const int8_t *dc) 00129 { 00130 int linesize= s->frame.linesize[0]; 00131 uint8_t *dest_y = s->frame.data[0] + (mb_y * 16* linesize ) + mb_x * 16; 00132 uint8_t *dest_cb = s->frame.data[1] + (mb_y * 8 * s->frame.linesize[1]) + mb_x * 8; 00133 uint8_t *dest_cr = s->frame.data[2] + (mb_y * 8 * s->frame.linesize[2]) + mb_x * 8; 00134 tgq_dconly(s,dest_y , linesize, dc[0]); 00135 tgq_dconly(s,dest_y + 8, linesize, dc[1]); 00136 tgq_dconly(s,dest_y + 8*linesize , linesize, dc[2]); 00137 tgq_dconly(s,dest_y + 8*linesize + 8, linesize, dc[3]); 00138 if(!(s->avctx->flags&CODEC_FLAG_GRAY)) { 00139 tgq_dconly(s,dest_cb, s->frame.linesize[1], dc[4]); 00140 tgq_dconly(s,dest_cr, s->frame.linesize[2], dc[5]); 00141 } 00142 } 00143 00144 static void tgq_decode_mb(TgqContext *s, int mb_y, int mb_x, const uint8_t **bs, const uint8_t *buf_end){ 00145 int mode; 00146 int i; 00147 int8_t dc[6]; 00148 00149 mode = bytestream_get_byte(bs); 00150 if (mode>buf_end-*bs) { 00151 av_log(s->avctx, AV_LOG_ERROR, "truncated macroblock\n"); 00152 return; 00153 } 00154 00155 if (mode>12) { 00156 GetBitContext gb; 00157 init_get_bits(&gb, *bs, mode*8); 00158 for(i=0; i<6; i++) 00159 tgq_decode_block(s, s->block[i], &gb); 00160 tgq_idct_put_mb(s, s->block, mb_x, mb_y); 00161 }else{ 00162 if (mode==3) { 00163 memset(dc, (*bs)[0], 4); 00164 dc[4] = (*bs)[1]; 00165 dc[5] = (*bs)[2]; 00166 }else if (mode==6) { 00167 memcpy(dc, *bs, 6); 00168 }else if (mode==12) { 00169 for(i=0; i<6; i++) 00170 dc[i] = (*bs)[i*2]; 00171 }else{ 00172 av_log(s->avctx, AV_LOG_ERROR, "unsupported mb mode %i\n", mode); 00173 } 00174 tgq_idct_put_mb_dconly(s, mb_x, mb_y, dc); 00175 } 00176 *bs += mode; 00177 } 00178 00179 static void tgq_calculate_qtable(TgqContext *s, int quant){ 00180 int i,j; 00181 const int a = (14*(100-quant))/100 + 1; 00182 const int b = (11*(100-quant))/100 + 4; 00183 for(j=0;j<8;j++) 00184 for(i=0;i<8;i++) 00185 if (s->avctx->idct_algo==FF_IDCT_EA) 00186 s->qtable[j*8+i] = ((a*(j+i)/(7+7) + b)*ff_inv_aanscales[j*8+i])>>(14-4); 00187 else 00188 s->qtable[j*8+i] = (a*(j+i)/(7+7) + b)<<3; 00189 } 00190 00191 static int tgq_decode_frame(AVCodecContext *avctx, 00192 void *data, int *data_size, 00193 AVPacket *avpkt){ 00194 const uint8_t *buf = avpkt->data; 00195 int buf_size = avpkt->size; 00196 const uint8_t *buf_start = buf; 00197 const uint8_t *buf_end = buf + buf_size; 00198 TgqContext *s = avctx->priv_data; 00199 int x,y; 00200 00201 int big_endian = AV_RL32(&buf[4]) > 0x000FFFFF; 00202 buf += 8; 00203 00204 if(8>buf_end-buf) { 00205 av_log(avctx, AV_LOG_WARNING, "truncated header\n"); 00206 return -1; 00207 } 00208 s->width = big_endian ? AV_RB16(&buf[0]) : AV_RL16(&buf[0]); 00209 s->height = big_endian ? AV_RB16(&buf[2]) : AV_RL16(&buf[2]); 00210 00211 if (s->avctx->width!=s->width || s->avctx->height!=s->height) { 00212 avcodec_set_dimensions(s->avctx, s->width, s->height); 00213 if (s->frame.data[0]) 00214 avctx->release_buffer(avctx, &s->frame); 00215 } 00216 tgq_calculate_qtable(s, buf[4]); 00217 buf += 8; 00218 00219 if (!s->frame.data[0]) { 00220 s->frame.key_frame = 1; 00221 s->frame.pict_type = FF_I_TYPE; 00222 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID; 00223 if (avctx->get_buffer(avctx, &s->frame)) { 00224 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00225 return -1; 00226 } 00227 } 00228 00229 for (y=0; y<(avctx->height+15)/16; y++) 00230 for (x=0; x<(avctx->width+15)/16; x++) 00231 tgq_decode_mb(s, y, x, &buf, buf_end); 00232 00233 *data_size = sizeof(AVFrame); 00234 *(AVFrame*)data = s->frame; 00235 00236 return buf-buf_start; 00237 } 00238 00239 static av_cold int tgq_decode_end(AVCodecContext *avctx){ 00240 TgqContext *s = avctx->priv_data; 00241 if (s->frame.data[0]) 00242 s->avctx->release_buffer(avctx, &s->frame); 00243 return 0; 00244 } 00245 00246 AVCodec eatgq_decoder = { 00247 "eatgq", 00248 AVMEDIA_TYPE_VIDEO, 00249 CODEC_ID_TGQ, 00250 sizeof(TgqContext), 00251 tgq_decode_init, 00252 NULL, 00253 tgq_decode_end, 00254 tgq_decode_frame, 00255 CODEC_CAP_DR1, 00256 .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGQ video"), 00257 };