mirror of
https://git.ffmpeg.org/ffmpeg.git
synced 2025-04-01 14:39:30 +00:00
avcodec/magicyuv: add 10 bit support
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
parent
bec8ea20c8
commit
6d09d6edbc
2
configure
vendored
2
configure
vendored
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user