yading@10: /* yading@10: * Escape 130 Video Decoder yading@10: * Copyright (C) 2008 Eli Friedman (eli.friedman gmail.com) 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 Street, Fifth Floor, Boston, MA 02110-1301 USA yading@10: */ yading@10: yading@10: #include "avcodec.h" yading@10: yading@10: #define BITSTREAM_READER_LE yading@10: #include "get_bits.h" yading@10: #include "internal.h" yading@10: yading@10: yading@10: typedef struct Escape130Context { yading@10: AVFrame frame; yading@10: uint8_t *bases; yading@10: } Escape130Context; yading@10: yading@10: /** yading@10: * Initialize the decoder yading@10: * @param avctx decoder context yading@10: * @return 0 success, negative on error yading@10: */ yading@10: static av_cold int escape130_decode_init(AVCodecContext *avctx) yading@10: { yading@10: Escape130Context *s = avctx->priv_data; yading@10: avctx->pix_fmt = AV_PIX_FMT_YUV420P; yading@10: avcodec_get_frame_defaults(&s->frame); yading@10: yading@10: if((avctx->width&1) || (avctx->height&1)){ yading@10: av_log(avctx, AV_LOG_ERROR, "Dimensions are not a multiple of the block size\n"); yading@10: return AVERROR(EINVAL); yading@10: } yading@10: yading@10: s->bases= av_malloc(avctx->width * avctx->height /4); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static av_cold int escape130_decode_close(AVCodecContext *avctx) yading@10: { yading@10: Escape130Context *s = avctx->priv_data; yading@10: yading@10: av_frame_unref(&s->frame); yading@10: yading@10: av_freep(&s->bases); yading@10: yading@10: return 0; yading@10: } yading@10: yading@10: static unsigned decode_skip_count(GetBitContext* gb) { yading@10: unsigned value; yading@10: // This function reads a maximum of 27 bits, yading@10: // which is within the padding space yading@10: if (get_bits_left(gb) < 1+3) yading@10: return -1; yading@10: yading@10: value = get_bits1(gb); yading@10: if (value) yading@10: return 0; yading@10: yading@10: value = get_bits(gb, 3); yading@10: if (value) yading@10: return value; yading@10: yading@10: value = get_bits(gb, 8); yading@10: if (value) yading@10: return value + 7; yading@10: yading@10: value = get_bits(gb, 15); yading@10: if (value) yading@10: return value + 262; yading@10: yading@10: return -1; yading@10: } yading@10: yading@10: /** yading@10: * Decode a single frame yading@10: * @param avctx decoder context yading@10: * @param data decoded frame yading@10: * @param got_frame have decoded frame yading@10: * @param buf input buffer yading@10: * @param buf_size input buffer size yading@10: * @return 0 success, -1 on error yading@10: */ yading@10: static int escape130_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: Escape130Context *s = avctx->priv_data; yading@10: yading@10: GetBitContext gb; yading@10: unsigned i; yading@10: int ret; yading@10: yading@10: uint8_t *old_y, *old_cb, *old_cr, yading@10: *new_y, *new_cb, *new_cr; yading@10: unsigned old_y_stride, old_cb_stride, old_cr_stride, yading@10: new_y_stride, new_cb_stride, new_cr_stride; yading@10: unsigned total_blocks = avctx->width * avctx->height / 4, yading@10: block_index, row_index = 0; yading@10: unsigned y[4] = {0}, cb = 16, cr = 16; yading@10: unsigned skip = -1; yading@10: unsigned y_base = 0; yading@10: uint8_t *yb= s->bases; yading@10: yading@10: AVFrame *frame = data; yading@10: yading@10: init_get_bits(&gb, buf, buf_size * 8); yading@10: yading@10: if (get_bits_left(&gb) < 128) yading@10: return -1; yading@10: yading@10: // Header; no useful information in here yading@10: skip_bits_long(&gb, 128); yading@10: yading@10: if ((ret = ff_get_buffer(avctx, frame, AV_GET_BUFFER_FLAG_REF)) < 0) yading@10: return ret; yading@10: yading@10: new_y = frame->data[0]; yading@10: new_cb = frame->data[1]; yading@10: new_cr = frame->data[2]; yading@10: new_y_stride = frame->linesize[0]; yading@10: new_cb_stride = frame->linesize[1]; yading@10: new_cr_stride = frame->linesize[2]; yading@10: old_y = s->frame.data[0]; yading@10: old_cb = s->frame.data[1]; yading@10: old_cr = s->frame.data[2]; yading@10: old_y_stride = s->frame.linesize[0]; yading@10: old_cb_stride = s->frame.linesize[1]; yading@10: old_cr_stride = s->frame.linesize[2]; yading@10: yading@10: av_log(avctx, AV_LOG_DEBUG, yading@10: "Strides: %i, %i\n", yading@10: new_y_stride, new_cb_stride); yading@10: yading@10: for (block_index = 0; block_index < total_blocks; block_index++) { yading@10: // Note that this call will make us skip the rest of the blocks yading@10: // if the frame prematurely ends yading@10: if (skip == -1) yading@10: skip = decode_skip_count(&gb); yading@10: yading@10: if (skip) { yading@10: if (old_y) { yading@10: y[0] = old_y[0] / 4; yading@10: y[1] = old_y[1] / 4; yading@10: y[2] = old_y[old_y_stride] / 4; yading@10: y[3] = old_y[old_y_stride+1] / 4; yading@10: y_base= yb[0]; yading@10: cb = old_cb[0] / 8; yading@10: cr = old_cr[0] / 8; yading@10: } else { yading@10: y_base=y[0] = y[1] = y[2] = y[3] = 0; yading@10: cb = cr = 16; yading@10: } yading@10: } else { yading@10: if (get_bits1(&gb)) { yading@10: static const uint8_t offset_table[] = {2, 4, 10, 20}; yading@10: static const int8_t sign_table[64][4] = yading@10: { {0, 0, 0, 0}, yading@10: {-1, 1, 0, 0}, yading@10: {1, -1, 0, 0}, yading@10: {-1, 0, 1, 0}, yading@10: {-1, 1, 1, 0}, yading@10: {0, -1, 1, 0}, yading@10: {1, -1, 1, 0}, yading@10: {-1, -1, 1, 0}, yading@10: {1, 0, -1, 0}, yading@10: {0, 1, -1, 0}, yading@10: {1, 1, -1, 0}, yading@10: {-1, 1, -1, 0}, yading@10: {1, -1, -1, 0}, yading@10: {-1, 0, 0, 1}, yading@10: {-1, 1, 0, 1}, yading@10: {0, -1, 0, 1}, yading@10: yading@10: {0, 0, 0, 0}, yading@10: {1, -1, 0, 1}, yading@10: {-1, -1, 0, 1}, yading@10: {-1, 0, 1, 1}, yading@10: {-1, 1, 1, 1}, yading@10: {0, -1, 1, 1}, yading@10: {1, -1, 1, 1}, yading@10: {-1, -1, 1, 1}, yading@10: {0, 0, -1, 1}, yading@10: {1, 0, -1, 1}, yading@10: {-1, 0, -1, 1}, yading@10: {0, 1, -1, 1}, yading@10: {1, 1, -1, 1}, yading@10: {-1, 1, -1, 1}, yading@10: {0, -1, -1, 1}, yading@10: {1, -1, -1, 1}, yading@10: yading@10: {0, 0, 0, 0}, yading@10: {-1, -1, -1, 1}, yading@10: {1, 0, 0, -1}, yading@10: {0, 1, 0, -1}, yading@10: {1, 1, 0, -1}, yading@10: {-1, 1, 0, -1}, yading@10: {1, -1, 0, -1}, yading@10: {0, 0, 1, -1}, yading@10: {1, 0, 1, -1}, yading@10: {-1, 0, 1, -1}, yading@10: {0, 1, 1, -1}, yading@10: {1, 1, 1, -1}, yading@10: {-1, 1, 1, -1}, yading@10: {0, -1, 1, -1}, yading@10: {1, -1, 1, -1}, yading@10: {-1, -1, 1, -1}, yading@10: yading@10: {0, 0, 0, 0}, yading@10: {1, 0, -1, -1}, yading@10: {0, 1, -1, -1}, yading@10: {1, 1, -1, -1}, yading@10: {-1, 1, -1, -1}, yading@10: {1, -1, -1, -1} }; yading@10: unsigned sign_selector = get_bits(&gb, 6); yading@10: unsigned difference_selector = get_bits(&gb, 2); yading@10: y_base = 2 * get_bits(&gb, 5); yading@10: for (i = 0; i < 4; i++) { yading@10: y[i] = av_clip((int)y_base + offset_table[difference_selector] * yading@10: sign_table[sign_selector][i], 0, 63); yading@10: } yading@10: } else if (get_bits1(&gb)) { yading@10: if (get_bits1(&gb)) { yading@10: y_base = get_bits(&gb, 6); yading@10: } else { yading@10: unsigned adjust_index = get_bits(&gb, 3); yading@10: static const int8_t adjust[] = {-4, -3, -2, -1, 1, 2, 3, 4}; yading@10: y_base = (y_base + adjust[adjust_index]) & 63; yading@10: } yading@10: for (i = 0; i < 4; i++) yading@10: y[i] = y_base; yading@10: } yading@10: yading@10: if (get_bits1(&gb)) { yading@10: if (get_bits1(&gb)) { yading@10: cb = get_bits(&gb, 5); yading@10: cr = get_bits(&gb, 5); yading@10: } else { yading@10: unsigned adjust_index = get_bits(&gb, 3); yading@10: static const int8_t adjust[2][8] = yading@10: { { 1, 1, 0, -1, -1, -1, 0, 1 }, yading@10: { 0, 1, 1, 1, 0, -1, -1, -1 } }; yading@10: cb = (cb + adjust[0][adjust_index]) & 31; yading@10: cr = (cr + adjust[1][adjust_index]) & 31; yading@10: } yading@10: } yading@10: } yading@10: *yb++= y_base; yading@10: yading@10: new_y[0] = y[0] * 4; yading@10: new_y[1] = y[1] * 4; yading@10: new_y[new_y_stride] = y[2] * 4; yading@10: new_y[new_y_stride + 1] = y[3] * 4; yading@10: *new_cb = cb * 8; yading@10: *new_cr = cr * 8; yading@10: yading@10: if (old_y) yading@10: old_y += 2, old_cb++, old_cr++; yading@10: new_y += 2, new_cb++, new_cr++; yading@10: row_index++; yading@10: if (avctx->width / 2 == row_index) { yading@10: row_index = 0; yading@10: if (old_y) { yading@10: old_y += old_y_stride * 2 - avctx->width; yading@10: old_cb += old_cb_stride - avctx->width / 2; yading@10: old_cr += old_cr_stride - avctx->width / 2; yading@10: } yading@10: new_y += new_y_stride * 2 - avctx->width; yading@10: new_cb += new_cb_stride - avctx->width / 2; yading@10: new_cr += new_cr_stride - avctx->width / 2; yading@10: } yading@10: yading@10: skip--; yading@10: } yading@10: yading@10: av_log(avctx, AV_LOG_DEBUG, yading@10: "Escape sizes: %i, %i\n", yading@10: buf_size, get_bits_count(&gb) / 8); yading@10: yading@10: av_frame_unref(&s->frame); yading@10: if ((ret = av_frame_ref(&s->frame, frame)) < 0) yading@10: return ret; yading@10: yading@10: *got_frame = 1; yading@10: yading@10: return buf_size; yading@10: } yading@10: yading@10: yading@10: AVCodec ff_escape130_decoder = { yading@10: .name = "escape130", yading@10: .type = AVMEDIA_TYPE_VIDEO, yading@10: .id = AV_CODEC_ID_ESCAPE130, yading@10: .priv_data_size = sizeof(Escape130Context), yading@10: .init = escape130_decode_init, yading@10: .close = escape130_decode_close, yading@10: .decode = escape130_decode_frame, yading@10: .capabilities = CODEC_CAP_DR1, yading@10: .long_name = NULL_IF_CONFIG_SMALL("Escape 130"), yading@10: };