Commit 6d09d6ed authored by Paul B Mahol's avatar Paul B Mahol

avcodec/magicyuv: add 10 bit support

Signed-off-by: 's avatarPaul B Mahol <onemda@gmail.com>
parent bec8ea20
......@@ -2441,7 +2441,7 @@ jv_decoder_select="blockdsp"
lagarith_decoder_select="huffyuvdsp"
ljpeg_encoder_select="aandcttables idctdsp jpegtables"
loco_decoder_select="golomb"
magicyuv_decoder_select="huffyuvdsp"
magicyuv_decoder_select="huffyuvdsp llviddsp"
mdec_decoder_select="blockdsp idctdsp mpegvideo"
metasound_decoder_select="lsp mdct sinewin"
mimic_decoder_select="blockdsp bswapdsp hpeldsp idctdsp"
......
......@@ -30,6 +30,7 @@
#include "get_bits.h"
#include "huffyuvdsp.h"
#include "internal.h"
#include "lossless_videodsp.h"
#include "thread.h"
typedef struct Slice {
......@@ -44,13 +45,14 @@ typedef enum Prediction {
} Prediction;
typedef struct HuffEntry {
uint8_t sym;
uint16_t sym;
uint8_t len;
uint32_t code;
} HuffEntry;
typedef struct MagicYUVContext {
AVFrame *p;
int max;
int slice_height;
int nb_slices;
int planes; // number of encoded planes in bitstream
......@@ -61,9 +63,13 @@ typedef struct MagicYUVContext {
int vshift[4];
Slice *slices[4]; // slice bitstream positions for each plane
unsigned int slices_size[4]; // slice sizes for each plane
uint8_t len[4][256]; // table of code lengths for each plane
uint8_t len[4][1024]; // table of code lengths for each plane
VLC vlc[4]; // VLC for each plane
int (*huff_build)(VLC *vlc, uint8_t *len);
int (*magy_decode_slice)(AVCodecContext *avctx, void *tdata,
int j, int threadnr);
HuffYUVDSPContext hdsp;
LLVidDSPContext llviddsp;
} MagicYUVContext;
static int huff_cmp_len(const void *a, const void *b)
......@@ -72,6 +78,42 @@ static int huff_cmp_len(const void *a, const void *b)
return (aa->len - bb->len) * 256 + aa->sym - bb->sym;
}
static int huff_cmp_len10(const void *a, const void *b)
{
const HuffEntry *aa = a, *bb = b;
return (aa->len - bb->len) * 1024 + aa->sym - bb->sym;
}
static int huff_build10(VLC *vlc, uint8_t *len)
{
HuffEntry he[1024];
uint32_t codes[1024];
uint8_t bits[1024];
uint16_t syms[1024];
uint32_t code;
int i;
for (i = 0; i < 1024; i++) {
he[i].sym = 1023 - i;
he[i].len = len[i];
}
AV_QSORT(he, 1024, HuffEntry, huff_cmp_len10);
code = 1;
for (i = 1023; i >= 0; i--) {
codes[i] = code >> (32 - he[i].len);
bits[i] = he[i].len;
syms[i] = he[i].sym;
code += 0x80000000u >> (he[i].len - 1);
}
ff_free_vlc(vlc);
return ff_init_vlc_sparse(vlc, FFMIN(he[1023].len, 12), 1024,
bits, sizeof(*bits), sizeof(*bits),
codes, sizeof(*codes), sizeof(*codes),
syms, sizeof(*syms), sizeof(*syms), 0);
}
static int huff_build(VLC *vlc, uint8_t *len)
{
HuffEntry he[256];
......@@ -102,6 +144,158 @@ static int huff_build(VLC *vlc, uint8_t *len)
syms, sizeof(*syms), sizeof(*syms), 0);
}
static void magicyuv_median_pred10(uint16_t *dst, const uint16_t *src1,
const uint16_t *diff, intptr_t w,
int *left, int *left_top)
{
int i;
uint16_t l, lt;
l = *left;
lt = *left_top;
for (i = 0; i < w; i++) {
l = mid_pred(l, src1[i], (l + src1[i] - lt)) + diff[i];
l &= 0x3FF;
lt = src1[i];
dst[i] = l;
}
*left = l;
*left_top = lt;
}
static int magy_decode_slice10(AVCodecContext *avctx, void *tdata,
int j, int threadnr)
{
MagicYUVContext *s = avctx->priv_data;
int interlaced = s->interlaced;
AVFrame *p = s->p;
int i, k, x;
GetBitContext gb;
uint16_t *dst;
for (i = 0; i < s->planes; i++) {
int left, lefttop, top;
int height = AV_CEIL_RSHIFT(FFMIN(s->slice_height, avctx->coded_height - j * s->slice_height), s->vshift[i]);
int width = AV_CEIL_RSHIFT(avctx->coded_width, s->hshift[i]);
int sheight = AV_CEIL_RSHIFT(s->slice_height, s->vshift[i]);
ptrdiff_t fake_stride = (p->linesize[i] / 2) * (1 + interlaced);
ptrdiff_t stride = p->linesize[i] / 2;
int flags, pred;
int ret = init_get_bits8(&gb, s->buf + s->slices[i][j].start,
s->slices[i][j].size);
if (ret < 0)
return ret;
flags = get_bits(&gb, 8);
pred = get_bits(&gb, 8);
dst = (uint16_t *)p->data[i] + j * sheight * stride;
if (flags & 1) {
for (k = 0; k < height; k++) {
for (x = 0; x < width; x++)
dst[x] = get_bits(&gb, 10);
dst += stride;
}
} else {
for (k = 0; k < height; k++) {
for (x = 0; x < width; x++) {
int pix;
if (get_bits_left(&gb) <= 0)
return AVERROR_INVALIDDATA;
pix = get_vlc2(&gb, s->vlc[i].table, s->vlc[i].bits, 3);
if (pix < 0)
return AVERROR_INVALIDDATA;
dst[x] = 1023 - pix;
}
dst += stride;
}
}
switch (pred) {
case LEFT:
dst = (uint16_t *)p->data[i] + j * sheight * stride;
s->llviddsp.add_hfyu_left_pred_int16(dst, dst, 1023, width, 0);
dst += stride;
if (interlaced) {
s->llviddsp.add_hfyu_left_pred_int16(dst, dst, 1023, width, 0);
dst += stride;
}
for (k = 1 + interlaced; k < height; k++) {
s->llviddsp.add_hfyu_left_pred_int16(dst, dst, 1023, width, dst[-fake_stride]);
dst += stride;
}
break;
case GRADIENT:
dst = (uint16_t *)p->data[i] + j * sheight * stride;
s->llviddsp.add_hfyu_left_pred_int16(dst, dst, 1023, width, 0);
left = lefttop = 0;
dst += stride;
if (interlaced) {
s->llviddsp.add_hfyu_left_pred_int16(dst, dst, 1023, width, 0);
left = lefttop = 0;
dst += stride;
}
for (k = 1 + interlaced; k < height; k++) {
top = dst[-fake_stride];
left = top + dst[0];
dst[0] = left & 0x3FF;
for (x = 1; x < width; x++) {
top = dst[x - fake_stride];
lefttop = dst[x - (fake_stride + 1)];
left += top - lefttop + dst[x];
dst[x] = left & 0x3FF;
}
dst += stride;
}
break;
case MEDIAN:
dst = (uint16_t *)p->data[i] + j * sheight * stride;
lefttop = left = dst[0];
s->llviddsp.add_hfyu_left_pred_int16(dst, dst, 1023, width, 0);
dst += stride;
if (interlaced) {
lefttop = left = dst[0];
s->llviddsp.add_hfyu_left_pred_int16(dst, dst, 1023, width, 0);
dst += stride;
}
for (k = 1 + interlaced; k < height; k++) {
magicyuv_median_pred10(dst, dst - fake_stride, dst, width, &left, &lefttop);
lefttop = left = dst[0];
dst += stride;
}
break;
default:
avpriv_request_sample(avctx, "Unknown prediction: %d", pred);
}
}
if (s->decorrelate) {
int height = FFMIN(s->slice_height, avctx->coded_height - j * s->slice_height);
int width = avctx->coded_width;
uint16_t *r = (uint16_t *)p->data[0] + j * s->slice_height * p->linesize[0] / 2;
uint16_t *g = (uint16_t *)p->data[1] + j * s->slice_height * p->linesize[1] / 2;
uint16_t *b = (uint16_t *)p->data[2] + j * s->slice_height * p->linesize[2] / 2;
for (i = 0; i < height; i++) {
for (k = 0; k < width; k++) {
b[k] = (b[k] + g[k]) & 0x3FF;
r[k] = (r[k] + g[k]) & 0x3FF;
}
b += p->linesize[0] / 2;
g += p->linesize[1] / 2;
r += p->linesize[2] / 2;
}
}
return 0;
}
static int magy_decode_slice(AVCodecContext *avctx, void *tdata,
int j, int threadnr)
{
......@@ -232,6 +426,45 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata,
return 0;
}
static int build_huffman(AVCodecContext *avctx, GetBitContext *gbit, int max)
{
MagicYUVContext *s = avctx->priv_data;
int i = 0, j = 0, k;
memset(s->len, 0, sizeof(s->len));
while (get_bits_left(gbit) >= 8) {
int b = get_bits(gbit, 4);
int x = get_bits(gbit, 4);
int l = get_bitsz(gbit, b) + 1;
for (k = 0; k < l; k++)
if (j + k < max)
s->len[i][j + k] = x;
j += l;
if (j == max) {
j = 0;
if (s->huff_build(&s->vlc[i], s->len[i])) {
av_log(avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
return AVERROR_INVALIDDATA;
}
i++;
if (i == s->planes) {
break;
}
} else if (j > max) {
return AVERROR_INVALIDDATA;
}
}
if (i != s->planes) {
av_log(avctx, AV_LOG_ERROR, "Huffman tables too short\n");
return AVERROR_INVALIDDATA;
}
return 0;
}
static int magy_decode_frame(AVCodecContext *avctx, void *data,
int *got_frame, AVPacket *avpkt)
{
......@@ -242,7 +475,7 @@ static int magy_decode_frame(AVCodecContext *avctx, void *data,
GetBitContext gbit;
uint32_t first_offset, offset, next_offset, header_size, slice_width;
int width, height, format, version, table_size;
int ret, i, j, k;
int ret, i, j;
bytestream2_init(&gbyte, avpkt->data, avpkt->size);
if (bytestream2_get_le32(&gbyte) != MKTAG('M', 'A', 'G', 'Y'))
......@@ -266,6 +499,9 @@ static int magy_decode_frame(AVCodecContext *avctx, void *data,
s->hshift[2] =
s->vshift[2] = 0;
s->decorrelate = 0;
s->max = 256;
s->huff_build = huff_build;
s->magy_decode_slice = magy_decode_slice;
format = bytestream2_get_byte(&gbyte);
switch (format) {
......@@ -298,6 +534,34 @@ static int magy_decode_frame(AVCodecContext *avctx, void *data,
case 0x6b:
avctx->pix_fmt = AV_PIX_FMT_GRAY8;
break;
case 0x6c:
avctx->pix_fmt = AV_PIX_FMT_YUV422P10;
s->hshift[1] =
s->hshift[2] = 1;
s->max = 1024;
s->huff_build = huff_build10;
s->magy_decode_slice = magy_decode_slice10;
break;
case 0x6d:
avctx->pix_fmt = AV_PIX_FMT_GBRP10;
s->decorrelate = 1;
s->max = 1024;
s->huff_build = huff_build10;
s->magy_decode_slice = magy_decode_slice10;
break;
case 0x6e:
avctx->pix_fmt = AV_PIX_FMT_GBRAP10;
s->decorrelate = 1;
s->max = 1024;
s->huff_build = huff_build10;
s->magy_decode_slice = magy_decode_slice10;
break;
case 0x73:
avctx->pix_fmt = AV_PIX_FMT_GRAY10;
s->max = 1024;
s->huff_build = huff_build10;
s->magy_decode_slice = magy_decode_slice10;
break;
default:
avpriv_request_sample(avctx, "Format 0x%X", format);
return AVERROR_PATCHWELCOME;
......@@ -375,37 +639,9 @@ static int magy_decode_frame(AVCodecContext *avctx, void *data,
if (ret < 0)
return ret;
memset(s->len, 0, sizeof(s->len));
j = i = 0;
while (get_bits_left(&gbit) >= 8) {
int b = get_bits(&gbit, 4);
int x = get_bits(&gbit, 4);
int l = get_bitsz(&gbit, b) + 1;
for (k = 0; k < l; k++)
if (j + k < 256)
s->len[i][j + k] = x;
j += l;
if (j == 256) {
j = 0;
if (huff_build(&s->vlc[i], s->len[i])) {
av_log(avctx, AV_LOG_ERROR, "Cannot build Huffman codes\n");
return AVERROR_INVALIDDATA;
}
i++;
if (i == s->planes) {
break;
}
} else if (j > 256) {
return AVERROR_INVALIDDATA;
}
}
if (i != s->planes) {
av_log(avctx, AV_LOG_ERROR, "Huffman tables too short\n");
return AVERROR_INVALIDDATA;
}
ret = build_huffman(avctx, &gbit, s->max);
if (ret < 0)
return ret;
p->pict_type = AV_PICTURE_TYPE_I;
p->key_frame = 1;
......@@ -415,10 +651,12 @@ static int magy_decode_frame(AVCodecContext *avctx, void *data,
s->buf = avpkt->data;
s->p = p;
avctx->execute2(avctx, magy_decode_slice, NULL, NULL, s->nb_slices);
avctx->execute2(avctx, s->magy_decode_slice, NULL, NULL, s->nb_slices);
if (avctx->pix_fmt == AV_PIX_FMT_GBRP ||
avctx->pix_fmt == AV_PIX_FMT_GBRAP) {
if (avctx->pix_fmt == AV_PIX_FMT_GBRP ||
avctx->pix_fmt == AV_PIX_FMT_GBRAP ||
avctx->pix_fmt == AV_PIX_FMT_GBRP10 ||
avctx->pix_fmt == AV_PIX_FMT_GBRAP10) {
FFSWAP(uint8_t*, p->data[0], p->data[1]);
FFSWAP(int, p->linesize[0], p->linesize[1]);
}
......@@ -447,6 +685,7 @@ static av_cold int magy_decode_init(AVCodecContext *avctx)
{
MagicYUVContext *s = avctx->priv_data;
ff_huffyuvdsp_init(&s->hdsp);
ff_llviddsp_init(&s->llviddsp, avctx);
return 0;
}
......
......@@ -42,7 +42,7 @@ void ff_llviddsp_init_x86(LLVidDSPContext *c, AVCodecContext *avctx)
c->diff_int16 = ff_diff_int16_mmx;
}
if (EXTERNAL_MMXEXT(cpu_flags) && pix_desc->comp[0].depth<16) {
if (EXTERNAL_MMXEXT(cpu_flags) && pix_desc && pix_desc->comp[0].depth<16) {
c->add_hfyu_median_pred_int16 = ff_add_hfyu_median_pred_int16_mmxext;
c->sub_hfyu_median_pred_int16 = ff_sub_hfyu_median_pred_int16_mmxext;
}
......
......@@ -275,6 +275,10 @@ const AVCodecTag ff_codec_movvideo_tags[] = {
{ AV_CODEC_ID_DXV, MKTAG('D', 'X', 'D', '3') },
{ AV_CODEC_ID_DXV, MKTAG('D', 'X', 'D', 'I') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', '0') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'A') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'G') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'Y', '2') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'R', 'G') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'R', 'A') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '8', 'G', '0') },
......
......@@ -428,6 +428,10 @@ const AVCodecTag ff_codec_bmp_tags[] = {
{ AV_CODEC_ID_M101, MKTAG('M', '1', '0', '1') },
{ AV_CODEC_ID_M101, MKTAG('M', '1', '0', '2') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', 'A', 'G', 'Y') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'A') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'R', 'G') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'G', '0') },
{ AV_CODEC_ID_MAGICYUV, MKTAG('M', '0', 'Y', '2') },
{ AV_CODEC_ID_YLC, MKTAG('Y', 'L', 'C', '0') },
{ AV_CODEC_ID_NONE, 0 }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment