|
|
|
/*
|
|
|
|
* 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 */
|