yading@10: /* yading@10: * Electronic Arts TQI Video Decoder yading@10: * Copyright (c) 2007-2009 Peter Ross yading@10: * yading@10: * This file is part of FFmpeg. yading@10: * yading@10: * FFmpeg is free software; you can redistribute it and/or yading@10: * modify it under the terms of the GNU Lesser General Public yading@10: * License as published by the Free Software Foundation; either yading@10: * version 2.1 of the License, or (at your option) any later version. yading@10: * yading@10: * FFmpeg is distributed in the hope that it will be useful, yading@10: * but WITHOUT ANY WARRANTY; without even the implied warranty of yading@10: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU yading@10: * Lesser General Public License for more details. yading@10: * yading@10: * You should have received a copy of the GNU Lesser General Public yading@10: * License along with FFmpeg; if not, write to the Free Software yading@10: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: /** yading@10: * @file yading@10: * Electronic Arts TQI Video Decoder yading@10: * @author Peter Ross yading@10: * @see http://wiki.multimedia.cx/index.php?title=Electronic_Arts_TQI yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: #include "get_bits.h" yading@10: #include "aandcttab.h" yading@10: #include "eaidct.h" yading@10: #include "internal.h" yading@10: #include "mpeg12.h" yading@10: #include "mpegvideo.h" yading@10: yading@10: typedef struct TqiContext { yading@10: MpegEncContext s; yading@10: void *bitstream_buf; yading@10: unsigned int bitstream_buf_size; yading@10: DECLARE_ALIGNED(16, int16_t, block)[6][64]; yading@10: } TqiContext; yading@10: yading@10: static av_cold int tqi_decode_init(AVCodecContext *avctx) yading@10: { yading@10: TqiContext *t = avctx->priv_data; yading@10: MpegEncContext *s = &t->s; yading@10: s->avctx = avctx; yading@10: ff_dsputil_init(&s->dsp, avctx); yading@10: ff_init_scantable_permutation(s->dsp.idct_permutation, FF_NO_IDCT_PERM); yading@10: ff_init_scantable(s->dsp.idct_permutation, &s->intra_scantable, ff_zigzag_direct); yading@10: s->qscale = 1; yading@10: avctx->time_base = (AVRational){1, 15}; yading@10: avctx->pix_fmt = AV_PIX_FMT_YUV420P; yading@10: ff_mpeg12_init_vlcs(); yading@10: return 0; yading@10: } yading@10: yading@10: static int tqi_decode_mb(MpegEncContext *s, int16_t (*block)[64]) yading@10: { yading@10: int n; yading@10: s->dsp.clear_blocks(block[0]); yading@10: for (n=0; n<6; n++) yading@10: if (ff_mpeg1_decode_block_intra(s, block[n], n) < 0) yading@10: return -1; yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static inline void tqi_idct_put(TqiContext *t, AVFrame *frame, int16_t (*block)[64]) yading@10: { yading@10: MpegEncContext *s = &t->s; yading@10: int linesize = frame->linesize[0]; yading@10: uint8_t *dest_y = frame->data[0] + (s->mb_y * 16* linesize ) + s->mb_x * 16; yading@10: uint8_t *dest_cb = frame->data[1] + (s->mb_y * 8 * frame->linesize[1]) + s->mb_x * 8; yading@10: uint8_t *dest_cr = frame->data[2] + (s->mb_y * 8 * frame->linesize[2]) + s->mb_x * 8; yading@10: yading@10: ff_ea_idct_put_c(dest_y , linesize, block[0]); yading@10: ff_ea_idct_put_c(dest_y + 8, linesize, block[1]); yading@10: ff_ea_idct_put_c(dest_y + 8*linesize , linesize, block[2]); yading@10: ff_ea_idct_put_c(dest_y + 8*linesize + 8, linesize, block[3]); yading@10: if(!(s->avctx->flags&CODEC_FLAG_GRAY)) { yading@10: ff_ea_idct_put_c(dest_cb, frame->linesize[1], block[4]); yading@10: ff_ea_idct_put_c(dest_cr, frame->linesize[2], block[5]); yading@10: } yading@10: } yading@10: yading@10: static void tqi_calculate_qtable(MpegEncContext *s, int quant) yading@10: { yading@10: const int qscale = (215 - 2*quant)*5; yading@10: int i; yading@10: s->intra_matrix[0] = (ff_inv_aanscales[0]*ff_mpeg1_default_intra_matrix[0])>>11; yading@10: for(i=1; i<64; i++) yading@10: s->intra_matrix[i] = (ff_inv_aanscales[i]*ff_mpeg1_default_intra_matrix[i]*qscale + 32)>>14; yading@10: } yading@10: yading@10: static int tqi_decode_frame(AVCodecContext *avctx, yading@10: void *data, int *got_frame, yading@10: AVPacket *avpkt) yading@10: { yading@10: const uint8_t *buf = avpkt->data; yading@10: int buf_size = avpkt->size; yading@10: const uint8_t *buf_end = buf+buf_size; yading@10: TqiContext *t = avctx->priv_data; yading@10: MpegEncContext *s = &t->s; yading@10: AVFrame *frame = data; yading@10: int ret; yading@10: yading@10: s->width = AV_RL16(&buf[0]); yading@10: s->height = AV_RL16(&buf[2]); yading@10: tqi_calculate_qtable(s, buf[4]); yading@10: buf += 8; yading@10: yading@10: if (s->avctx->width!=s->width || s->avctx->height!=s->height) yading@10: avcodec_set_dimensions(s->avctx, s->width, s->height); yading@10: yading@10: if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) yading@10: return ret; yading@10: yading@10: av_fast_padded_malloc(&t->bitstream_buf, &t->bitstream_buf_size, yading@10: buf_end - buf); yading@10: if (!t->bitstream_buf) yading@10: return AVERROR(ENOMEM); yading@10: s->dsp.bswap_buf(t->bitstream_buf, (const uint32_t*)buf, (buf_end-buf)/4); yading@10: init_get_bits(&s->gb, t->bitstream_buf, 8*(buf_end-buf)); yading@10: yading@10: s->last_dc[0] = s->last_dc[1] = s->last_dc[2] = 0; yading@10: for (s->mb_y=0; s->mb_y<(avctx->height+15)/16; s->mb_y++) yading@10: for (s->mb_x=0; s->mb_x<(avctx->width+15)/16; s->mb_x++) yading@10: { yading@10: if (tqi_decode_mb(s, t->block) < 0) yading@10: goto end; yading@10: tqi_idct_put(t, frame, t->block); yading@10: } yading@10: end: yading@10: yading@10: *got_frame = 1; yading@10: return buf_size; yading@10: } yading@10: yading@10: static av_cold int tqi_decode_end(AVCodecContext *avctx) yading@10: { yading@10: TqiContext *t = avctx->priv_data; yading@10: av_free(t->bitstream_buf); yading@10: return 0; yading@10: } yading@10: yading@10: AVCodec ff_eatqi_decoder = { yading@10: .name = "eatqi", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_TQI, yading@10: .priv_data_size = sizeof(TqiContext), yading@10: .init = tqi_decode_init, yading@10: .close = tqi_decode_end, yading@10: .decode = tqi_decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("Electronic Arts TQI Video"), yading@10: };