/* * ScreenPressor decoder * * Copyright (c) 2017 Paul B Mahol * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef AVCODEC_SCPR_H #define AVCODEC_SCPR_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include "avcodec.h" #include "bytestream.h" #include "internal.h" #include "scpr3.h" typedef struct RangeCoder { uint32_t code; uint32_t range; uint32_t code1; } RangeCoder; typedef struct PixelModel { uint32_t freq[256]; uint32_t lookup[16]; uint32_t total_freq; } PixelModel; typedef struct SCPRContext { int version; AVFrame *last_frame; AVFrame *current_frame; GetByteContext gb; RangeCoder rc; PixelModel pixel_model[3][4096]; uint32_t op_model[6][7]; uint32_t run_model[6][257]; uint32_t range_model[257]; uint32_t count_model[257]; uint32_t fill_model[6]; uint32_t sxy_model[4][17]; uint32_t mv_model[2][513]; uint32_t nbx, nby; uint32_t nbcount; uint32_t *blocks; uint32_t cbits; int cxshift; PixelModel3 pixel_model3[3][4096]; RunModel3 run_model3[6]; RunModel3 range_model3; RunModel3 count_model3; FillModel3 fill_model3; SxyModel3 sxy_model3[4]; MVModel3 mv_model3[2]; OpModel3 op_model3[6]; int (*get_freq)(RangeCoder *rc, uint32_t total_freq, uint32_t *freq); int (*decode)(GetByteContext *gb, RangeCoder *rc, uint32_t cumFreq, uint32_t freq, uint32_t total_freq); } SCPRContext; static int decode_run_i(AVCodecContext *avctx, uint32_t ptype, int run, int *px, int *py, uint32_t clr, uint32_t *dst, int linesize, uint32_t *plx, uint32_t *ply, uint32_t backstep, int off, int *cx, int *cx1) { uint32_t r, g, b; int z; int x = *px, y = *py; uint32_t lx = *plx, ly = *ply; if (y >= avctx->height) return AVERROR_INVALIDDATA; switch (ptype) { case 0: while (run-- > 0) { dst[y * linesize + x] = clr; lx = x; ly = y; (x)++; if (x >= avctx->width) { x = 0; (y)++; if (y >= avctx->height && run) return AVERROR_INVALIDDATA; } } break; case 1: while (run-- > 0) { dst[y * linesize + x] = dst[ly * linesize + lx]; lx = x; ly = y; (x)++; if (x >= avctx->width) { x = 0; (y)++; if (y >= avctx->height && run) return AVERROR_INVALIDDATA; } } clr = dst[ly * linesize + lx]; break; case 2: if (y < 1) return AVERROR_INVALIDDATA; while (run-- > 0) { clr = dst[y * linesize + x + off + 1]; dst[y * linesize + x] = clr; lx = x; ly = y; (x)++; if (x >= avctx->width) { x = 0; (y)++; if (y >= avctx->height && run) return AVERROR_INVALIDDATA; } } break; case 4: if (y < 1 || (y == 1 && x == 0)) return AVERROR_INVALIDDATA; while (run-- > 0) { uint8_t *odst = (uint8_t *)dst; int off1 = (ly * linesize + lx) * 4; int off2 = ((y * linesize + x) + off) * 4; if (x == 0) { z = backstep * 4; } else { z = 0; } r = odst[off1] + odst[off2 + 4] - odst[off2 - z ]; g = odst[off1 + 1] + odst[off2 + 5] - odst[off2 - z + 1]; b = odst[off1 + 2] + odst[off2 + 6] - odst[off2 - z + 2]; clr = ((b & 0xFF) << 16) + ((g & 0xFF) << 8) + (r & 0xFF); dst[y * linesize + x] = clr; lx = x; ly = y; (x)++; if (x >= avctx->width) { x = 0; (y)++; if (y >= avctx->height && run) return AVERROR_INVALIDDATA; } } break; case 5: if (y < 1 || (y == 1 && x == 0)) return AVERROR_INVALIDDATA; while (run-- > 0) { if (x == 0) { z = backstep; } else { z = 0; } clr = dst[y * linesize + x + off - z]; dst[y * linesize + x] = clr; lx = x; ly = y; (x)++; if (x >= avctx->width) { x = 0; (y)++; if (y >= avctx->height && run) return AVERROR_INVALIDDATA; } } break; } *px = x; *py = y; *plx= lx; *ply= ly; if (avctx->bits_per_coded_sample == 16) { *cx1 = (clr & 0x3F00) >> 2; *cx = (clr & 0x3FFFFF) >> 16; } else { *cx1 = (clr & 0xFC00) >> 4; *cx = (clr & 0xFFFFFF) >> 18; } return 0; } static int decode_run_p(AVCodecContext *avctx, uint32_t ptype, int run, int x, int y, uint32_t clr, uint32_t *dst, uint32_t *prev, int linesize, int plinesize, uint32_t *bx, uint32_t *by, uint32_t backstep, int sx1, int sx2, int *cx, int *cx1) { uint32_t r, g, b; int z; switch (ptype) { case 0: while (run-- > 0) { if (*by >= avctx->height) return AVERROR_INVALIDDATA; dst[*by * linesize + *bx] = clr; (*bx)++; if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { *bx = x * 16 + sx1; (*by)++; } } break; case 1: while (run-- > 0) { if (*bx == 0) { if (*by < 1) return AVERROR_INVALIDDATA; z = backstep; } else { z = 0; } if (*by >= avctx->height) return AVERROR_INVALIDDATA; clr = dst[*by * linesize + *bx - 1 - z]; dst[*by * linesize + *bx] = clr; (*bx)++; if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { *bx = x * 16 + sx1; (*by)++; } } break; case 2: while (run-- > 0) { if (*by < 1 || *by >= avctx->height) return AVERROR_INVALIDDATA; clr = dst[(*by - 1) * linesize + *bx]; dst[*by * linesize + *bx] = clr; (*bx)++; if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { *bx = x * 16 + sx1; (*by)++; } } break; case 3: while (run-- > 0) { if (*by >= avctx->height) return AVERROR_INVALIDDATA; clr = prev[*by * plinesize + *bx]; dst[*by * linesize + *bx] = clr; (*bx)++; if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { *bx = x * 16 + sx1; (*by)++; } } break; case 4: while (run-- > 0) { uint8_t *odst = (uint8_t *)dst; if (*by < 1 || *by >= avctx->height) return AVERROR_INVALIDDATA; if (*bx == 0) { if (*by < 2) return AVERROR_INVALIDDATA; z = backstep; } else { z = 0; } r = odst[((*by - 1) * linesize + *bx) * 4] + odst[(*by * linesize + *bx - 1 - z) * 4] - odst[((*by - 1) * linesize + *bx - 1 - z) * 4]; g = odst[((*by - 1) * linesize + *bx) * 4 + 1] + odst[(*by * linesize + *bx - 1 - z) * 4 + 1] - odst[((*by - 1) * linesize + *bx - 1 - z) * 4 + 1]; b = odst[((*by - 1) * linesize + *bx) * 4 + 2] + odst[(*by * linesize + *bx - 1 - z) * 4 + 2] - odst[((*by - 1) * linesize + *bx - 1 - z) * 4 + 2]; clr = ((b & 0xFF) << 16) + ((g & 0xFF) << 8) + (r & 0xFF); dst[*by * linesize + *bx] = clr; (*bx)++; if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { *bx = x * 16 + sx1; (*by)++; } } break; case 5: while (run-- > 0) { if (*by < 1 || *by >= avctx->height) return AVERROR_INVALIDDATA; if (*bx == 0) { if (*by < 2) return AVERROR_INVALIDDATA; z = backstep; } else { z = 0; } clr = dst[(*by - 1) * linesize + *bx - 1 - z]; dst[*by * linesize + *bx] = clr; (*bx)++; if (*bx >= x * 16 + sx2 || *bx >= avctx->width) { *bx = x * 16 + sx1; (*by)++; } } break; } if (avctx->bits_per_coded_sample == 16) { *cx1 = (clr & 0x3F00) >> 2; *cx = (clr & 0x3FFFFF) >> 16; } else { *cx1 = (clr & 0xFC00) >> 4; *cx = (clr & 0xFFFFFF) >> 18; } return 0; } #endif /* AVCODEC_SCPR_H */