1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * Electronic Arts TGQ Video Decoder 3cabdff1aSopenharmony_ci * Copyright (c) 2007-2008 Peter Ross <pross@xvid.org> 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci/** 23cabdff1aSopenharmony_ci * @file 24cabdff1aSopenharmony_ci * Electronic Arts TGQ Video Decoder 25cabdff1aSopenharmony_ci * @author Peter Ross <pross@xvid.org> 26cabdff1aSopenharmony_ci * 27cabdff1aSopenharmony_ci * Technical details here: 28cabdff1aSopenharmony_ci * http://wiki.multimedia.cx/index.php?title=Electronic_Arts_TGQ 29cabdff1aSopenharmony_ci */ 30cabdff1aSopenharmony_ci 31cabdff1aSopenharmony_ci#define BITSTREAM_READER_LE 32cabdff1aSopenharmony_ci 33cabdff1aSopenharmony_ci#include "libavutil/mem_internal.h" 34cabdff1aSopenharmony_ci 35cabdff1aSopenharmony_ci#include "aandcttab.h" 36cabdff1aSopenharmony_ci#include "avcodec.h" 37cabdff1aSopenharmony_ci#include "bytestream.h" 38cabdff1aSopenharmony_ci#include "codec_internal.h" 39cabdff1aSopenharmony_ci#include "eaidct.h" 40cabdff1aSopenharmony_ci#include "get_bits.h" 41cabdff1aSopenharmony_ci#include "idctdsp.h" 42cabdff1aSopenharmony_ci#include "internal.h" 43cabdff1aSopenharmony_ci 44cabdff1aSopenharmony_citypedef struct TgqContext { 45cabdff1aSopenharmony_ci AVCodecContext *avctx; 46cabdff1aSopenharmony_ci int width, height; 47cabdff1aSopenharmony_ci ScanTable scantable; 48cabdff1aSopenharmony_ci int qtable[64]; 49cabdff1aSopenharmony_ci DECLARE_ALIGNED(16, int16_t, block)[6][64]; 50cabdff1aSopenharmony_ci GetByteContext gb; 51cabdff1aSopenharmony_ci} TgqContext; 52cabdff1aSopenharmony_ci 53cabdff1aSopenharmony_cistatic av_cold int tgq_decode_init(AVCodecContext *avctx) 54cabdff1aSopenharmony_ci{ 55cabdff1aSopenharmony_ci TgqContext *s = avctx->priv_data; 56cabdff1aSopenharmony_ci uint8_t idct_permutation[64]; 57cabdff1aSopenharmony_ci s->avctx = avctx; 58cabdff1aSopenharmony_ci ff_init_scantable_permutation(idct_permutation, FF_IDCT_PERM_NONE); 59cabdff1aSopenharmony_ci ff_init_scantable(idct_permutation, &s->scantable, ff_zigzag_direct); 60cabdff1aSopenharmony_ci avctx->framerate = (AVRational){ 15, 1 }; 61cabdff1aSopenharmony_ci avctx->pix_fmt = AV_PIX_FMT_YUV420P; 62cabdff1aSopenharmony_ci return 0; 63cabdff1aSopenharmony_ci} 64cabdff1aSopenharmony_ci 65cabdff1aSopenharmony_cistatic int tgq_decode_block(TgqContext *s, int16_t block[64], GetBitContext *gb) 66cabdff1aSopenharmony_ci{ 67cabdff1aSopenharmony_ci uint8_t *perm = s->scantable.permutated; 68cabdff1aSopenharmony_ci int i, j, value; 69cabdff1aSopenharmony_ci block[0] = get_sbits(gb, 8) * s->qtable[0]; 70cabdff1aSopenharmony_ci for (i = 1; i < 64;) { 71cabdff1aSopenharmony_ci switch (show_bits(gb, 3)) { 72cabdff1aSopenharmony_ci case 4: 73cabdff1aSopenharmony_ci if (i >= 63) 74cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 75cabdff1aSopenharmony_ci block[perm[i++]] = 0; 76cabdff1aSopenharmony_ci case 0: 77cabdff1aSopenharmony_ci block[perm[i++]] = 0; 78cabdff1aSopenharmony_ci skip_bits(gb, 3); 79cabdff1aSopenharmony_ci break; 80cabdff1aSopenharmony_ci case 5: 81cabdff1aSopenharmony_ci case 1: 82cabdff1aSopenharmony_ci skip_bits(gb, 2); 83cabdff1aSopenharmony_ci value = get_bits(gb, 6); 84cabdff1aSopenharmony_ci if (value > 64 - i) 85cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 86cabdff1aSopenharmony_ci for (j = 0; j < value; j++) 87cabdff1aSopenharmony_ci block[perm[i++]] = 0; 88cabdff1aSopenharmony_ci break; 89cabdff1aSopenharmony_ci case 6: 90cabdff1aSopenharmony_ci skip_bits(gb, 3); 91cabdff1aSopenharmony_ci block[perm[i]] = -s->qtable[perm[i]]; 92cabdff1aSopenharmony_ci i++; 93cabdff1aSopenharmony_ci break; 94cabdff1aSopenharmony_ci case 2: 95cabdff1aSopenharmony_ci skip_bits(gb, 3); 96cabdff1aSopenharmony_ci block[perm[i]] = s->qtable[perm[i]]; 97cabdff1aSopenharmony_ci i++; 98cabdff1aSopenharmony_ci break; 99cabdff1aSopenharmony_ci case 7: // 111b 100cabdff1aSopenharmony_ci case 3: // 011b 101cabdff1aSopenharmony_ci skip_bits(gb, 2); 102cabdff1aSopenharmony_ci if (show_bits(gb, 6) == 0x3F) { 103cabdff1aSopenharmony_ci skip_bits(gb, 6); 104cabdff1aSopenharmony_ci block[perm[i]] = get_sbits(gb, 8) * s->qtable[perm[i]]; 105cabdff1aSopenharmony_ci } else { 106cabdff1aSopenharmony_ci block[perm[i]] = get_sbits(gb, 6) * s->qtable[perm[i]]; 107cabdff1aSopenharmony_ci } 108cabdff1aSopenharmony_ci i++; 109cabdff1aSopenharmony_ci break; 110cabdff1aSopenharmony_ci } 111cabdff1aSopenharmony_ci } 112cabdff1aSopenharmony_ci block[0] += 128 << 4; 113cabdff1aSopenharmony_ci return 0; 114cabdff1aSopenharmony_ci} 115cabdff1aSopenharmony_ci 116cabdff1aSopenharmony_cistatic void tgq_idct_put_mb(TgqContext *s, int16_t (*block)[64], AVFrame *frame, 117cabdff1aSopenharmony_ci int mb_x, int mb_y) 118cabdff1aSopenharmony_ci{ 119cabdff1aSopenharmony_ci ptrdiff_t linesize = frame->linesize[0]; 120cabdff1aSopenharmony_ci uint8_t *dest_y = frame->data[0] + (mb_y * 16 * linesize) + mb_x * 16; 121cabdff1aSopenharmony_ci uint8_t *dest_cb = frame->data[1] + (mb_y * 8 * frame->linesize[1]) + mb_x * 8; 122cabdff1aSopenharmony_ci uint8_t *dest_cr = frame->data[2] + (mb_y * 8 * frame->linesize[2]) + mb_x * 8; 123cabdff1aSopenharmony_ci 124cabdff1aSopenharmony_ci ff_ea_idct_put_c(dest_y , linesize, block[0]); 125cabdff1aSopenharmony_ci ff_ea_idct_put_c(dest_y + 8, linesize, block[1]); 126cabdff1aSopenharmony_ci ff_ea_idct_put_c(dest_y + 8 * linesize , linesize, block[2]); 127cabdff1aSopenharmony_ci ff_ea_idct_put_c(dest_y + 8 * linesize + 8, linesize, block[3]); 128cabdff1aSopenharmony_ci if (!(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { 129cabdff1aSopenharmony_ci ff_ea_idct_put_c(dest_cb, frame->linesize[1], block[4]); 130cabdff1aSopenharmony_ci ff_ea_idct_put_c(dest_cr, frame->linesize[2], block[5]); 131cabdff1aSopenharmony_ci } 132cabdff1aSopenharmony_ci} 133cabdff1aSopenharmony_ci 134cabdff1aSopenharmony_cistatic inline void tgq_dconly(TgqContext *s, unsigned char *dst, 135cabdff1aSopenharmony_ci ptrdiff_t dst_stride, int dc) 136cabdff1aSopenharmony_ci{ 137cabdff1aSopenharmony_ci int level = av_clip_uint8((dc*s->qtable[0] + 2056) >> 4); 138cabdff1aSopenharmony_ci int j; 139cabdff1aSopenharmony_ci for (j = 0; j < 8; j++) 140cabdff1aSopenharmony_ci memset(dst + j * dst_stride, level, 8); 141cabdff1aSopenharmony_ci} 142cabdff1aSopenharmony_ci 143cabdff1aSopenharmony_cistatic void tgq_idct_put_mb_dconly(TgqContext *s, AVFrame *frame, 144cabdff1aSopenharmony_ci int mb_x, int mb_y, const int8_t *dc) 145cabdff1aSopenharmony_ci{ 146cabdff1aSopenharmony_ci ptrdiff_t linesize = frame->linesize[0]; 147cabdff1aSopenharmony_ci uint8_t *dest_y = frame->data[0] + (mb_y * 16 * linesize) + mb_x * 16; 148cabdff1aSopenharmony_ci uint8_t *dest_cb = frame->data[1] + (mb_y * 8 * frame->linesize[1]) + mb_x * 8; 149cabdff1aSopenharmony_ci uint8_t *dest_cr = frame->data[2] + (mb_y * 8 * frame->linesize[2]) + mb_x * 8; 150cabdff1aSopenharmony_ci tgq_dconly(s, dest_y, linesize, dc[0]); 151cabdff1aSopenharmony_ci tgq_dconly(s, dest_y + 8, linesize, dc[1]); 152cabdff1aSopenharmony_ci tgq_dconly(s, dest_y + 8 * linesize, linesize, dc[2]); 153cabdff1aSopenharmony_ci tgq_dconly(s, dest_y + 8 * linesize + 8, linesize, dc[3]); 154cabdff1aSopenharmony_ci if (!(s->avctx->flags & AV_CODEC_FLAG_GRAY)) { 155cabdff1aSopenharmony_ci tgq_dconly(s, dest_cb, frame->linesize[1], dc[4]); 156cabdff1aSopenharmony_ci tgq_dconly(s, dest_cr, frame->linesize[2], dc[5]); 157cabdff1aSopenharmony_ci } 158cabdff1aSopenharmony_ci} 159cabdff1aSopenharmony_ci 160cabdff1aSopenharmony_cistatic int tgq_decode_mb(TgqContext *s, AVFrame *frame, int mb_y, int mb_x) 161cabdff1aSopenharmony_ci{ 162cabdff1aSopenharmony_ci int mode; 163cabdff1aSopenharmony_ci int i; 164cabdff1aSopenharmony_ci int8_t dc[6]; 165cabdff1aSopenharmony_ci 166cabdff1aSopenharmony_ci mode = bytestream2_get_byte(&s->gb); 167cabdff1aSopenharmony_ci if (mode > 12) { 168cabdff1aSopenharmony_ci GetBitContext gb; 169cabdff1aSopenharmony_ci int ret = init_get_bits8(&gb, s->gb.buffer, FFMIN(bytestream2_get_bytes_left(&s->gb), mode)); 170cabdff1aSopenharmony_ci if (ret < 0) 171cabdff1aSopenharmony_ci return ret; 172cabdff1aSopenharmony_ci 173cabdff1aSopenharmony_ci for (i = 0; i < 6; i++) { 174cabdff1aSopenharmony_ci int ret = tgq_decode_block(s, s->block[i], &gb); 175cabdff1aSopenharmony_ci if (ret < 0) 176cabdff1aSopenharmony_ci return ret; 177cabdff1aSopenharmony_ci } 178cabdff1aSopenharmony_ci tgq_idct_put_mb(s, s->block, frame, mb_x, mb_y); 179cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, mode); 180cabdff1aSopenharmony_ci } else { 181cabdff1aSopenharmony_ci if (mode == 3) { 182cabdff1aSopenharmony_ci memset(dc, bytestream2_get_byte(&s->gb), 4); 183cabdff1aSopenharmony_ci dc[4] = bytestream2_get_byte(&s->gb); 184cabdff1aSopenharmony_ci dc[5] = bytestream2_get_byte(&s->gb); 185cabdff1aSopenharmony_ci } else if (mode == 6) { 186cabdff1aSopenharmony_ci bytestream2_get_buffer(&s->gb, dc, 6); 187cabdff1aSopenharmony_ci } else if (mode == 12) { 188cabdff1aSopenharmony_ci for (i = 0; i < 6; i++) { 189cabdff1aSopenharmony_ci dc[i] = bytestream2_get_byte(&s->gb); 190cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, 1); 191cabdff1aSopenharmony_ci } 192cabdff1aSopenharmony_ci } else { 193cabdff1aSopenharmony_ci av_log(s->avctx, AV_LOG_ERROR, "unsupported mb mode %i\n", mode); 194cabdff1aSopenharmony_ci return -1; 195cabdff1aSopenharmony_ci } 196cabdff1aSopenharmony_ci tgq_idct_put_mb_dconly(s, frame, mb_x, mb_y, dc); 197cabdff1aSopenharmony_ci } 198cabdff1aSopenharmony_ci return 0; 199cabdff1aSopenharmony_ci} 200cabdff1aSopenharmony_ci 201cabdff1aSopenharmony_cistatic void tgq_calculate_qtable(TgqContext *s, int quant) 202cabdff1aSopenharmony_ci{ 203cabdff1aSopenharmony_ci int i, j; 204cabdff1aSopenharmony_ci const int a = (14 * (100 - quant)) / 100 + 1; 205cabdff1aSopenharmony_ci const int b = (11 * (100 - quant)) / 100 + 4; 206cabdff1aSopenharmony_ci for (j = 0; j < 8; j++) 207cabdff1aSopenharmony_ci for (i = 0; i < 8; i++) 208cabdff1aSopenharmony_ci s->qtable[j * 8 + i] = ((a * (j + i) / (7 + 7) + b) * 209cabdff1aSopenharmony_ci ff_inv_aanscales[j * 8 + i]) >> (14 - 4); 210cabdff1aSopenharmony_ci} 211cabdff1aSopenharmony_ci 212cabdff1aSopenharmony_cistatic int tgq_decode_frame(AVCodecContext *avctx, AVFrame *frame, 213cabdff1aSopenharmony_ci int *got_frame, AVPacket *avpkt) 214cabdff1aSopenharmony_ci{ 215cabdff1aSopenharmony_ci const uint8_t *buf = avpkt->data; 216cabdff1aSopenharmony_ci int buf_size = avpkt->size; 217cabdff1aSopenharmony_ci TgqContext *s = avctx->priv_data; 218cabdff1aSopenharmony_ci int x, y, ret; 219cabdff1aSopenharmony_ci int big_endian; 220cabdff1aSopenharmony_ci 221cabdff1aSopenharmony_ci if (buf_size < 16) { 222cabdff1aSopenharmony_ci av_log(avctx, AV_LOG_WARNING, "truncated header\n"); 223cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 224cabdff1aSopenharmony_ci } 225cabdff1aSopenharmony_ci big_endian = AV_RL32(&buf[4]) > 0x000FFFFF; 226cabdff1aSopenharmony_ci bytestream2_init(&s->gb, buf + 8, buf_size - 8); 227cabdff1aSopenharmony_ci if (big_endian) { 228cabdff1aSopenharmony_ci s->width = bytestream2_get_be16u(&s->gb); 229cabdff1aSopenharmony_ci s->height = bytestream2_get_be16u(&s->gb); 230cabdff1aSopenharmony_ci } else { 231cabdff1aSopenharmony_ci s->width = bytestream2_get_le16u(&s->gb); 232cabdff1aSopenharmony_ci s->height = bytestream2_get_le16u(&s->gb); 233cabdff1aSopenharmony_ci } 234cabdff1aSopenharmony_ci 235cabdff1aSopenharmony_ci ret = ff_set_dimensions(s->avctx, s->width, s->height); 236cabdff1aSopenharmony_ci if (ret < 0) 237cabdff1aSopenharmony_ci return ret; 238cabdff1aSopenharmony_ci 239cabdff1aSopenharmony_ci tgq_calculate_qtable(s, bytestream2_get_byteu(&s->gb)); 240cabdff1aSopenharmony_ci bytestream2_skip(&s->gb, 3); 241cabdff1aSopenharmony_ci 242cabdff1aSopenharmony_ci if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) 243cabdff1aSopenharmony_ci return ret; 244cabdff1aSopenharmony_ci frame->key_frame = 1; 245cabdff1aSopenharmony_ci frame->pict_type = AV_PICTURE_TYPE_I; 246cabdff1aSopenharmony_ci 247cabdff1aSopenharmony_ci for (y = 0; y < FFALIGN(avctx->height, 16) >> 4; y++) 248cabdff1aSopenharmony_ci for (x = 0; x < FFALIGN(avctx->width, 16) >> 4; x++) 249cabdff1aSopenharmony_ci if (tgq_decode_mb(s, frame, y, x) < 0) 250cabdff1aSopenharmony_ci return AVERROR_INVALIDDATA; 251cabdff1aSopenharmony_ci 252cabdff1aSopenharmony_ci *got_frame = 1; 253cabdff1aSopenharmony_ci 254cabdff1aSopenharmony_ci return avpkt->size; 255cabdff1aSopenharmony_ci} 256cabdff1aSopenharmony_ci 257cabdff1aSopenharmony_ciconst FFCodec ff_eatgq_decoder = { 258cabdff1aSopenharmony_ci .p.name = "eatgq", 259cabdff1aSopenharmony_ci .p.long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TGQ video"), 260cabdff1aSopenharmony_ci .p.type = AVMEDIA_TYPE_VIDEO, 261cabdff1aSopenharmony_ci .p.id = AV_CODEC_ID_TGQ, 262cabdff1aSopenharmony_ci .priv_data_size = sizeof(TgqContext), 263cabdff1aSopenharmony_ci .init = tgq_decode_init, 264cabdff1aSopenharmony_ci FF_CODEC_DECODE_CB(tgq_decode_frame), 265cabdff1aSopenharmony_ci .p.capabilities = AV_CODEC_CAP_DR1, 266cabdff1aSopenharmony_ci .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 267cabdff1aSopenharmony_ci}; 268