aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2016-12-19 23:21:49 +0100
committerPaul B Mahol <onemda@gmail.com>2016-12-20 13:32:15 +0100
commit6d09d6edbc464454a620e3ecf64fe752b5cfa9cc (patch)
tree4a8fb765c9a195325aa3c9c7ade8255d36410897
parentbec8ea20c88e89dbfbe89c590a74c9818dfcfcce (diff)
downloadffmpeg-6d09d6edbc464454a620e3ecf64fe752b5cfa9cc.tar.gz
avcodec/magicyuv: add 10 bit support
Signed-off-by: Paul B Mahol <onemda@gmail.com>
-rwxr-xr-xconfigure2
-rw-r--r--libavcodec/magicyuv.c313
-rw-r--r--libavcodec/x86/lossless_videodsp_init.c2
-rw-r--r--libavformat/isom.c4
-rw-r--r--libavformat/riff.c4
5 files changed, 286 insertions, 39 deletions
diff --git a/configure b/configure
index 9dfd006698..e2e171e150 100755
--- a/configure
+++ b/configure
@@ -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"
diff --git a/libavcodec/magicyuv.c b/libavcodec/magicyuv.c
index 2c312bec17..16d70274a1 100644
--- a/libavcodec/magicyuv.c
+++ b/libavcodec/magicyuv.c
@@ -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;
}
diff --git a/libavcodec/x86/lossless_videodsp_init.c b/libavcodec/x86/lossless_videodsp_init.c
index b0fbcfef8f..548d0433e1 100644
--- a/libavcodec/x86/lossless_videodsp_init.c
+++ b/libavcodec/x86/lossless_videodsp_init.c
@@ -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;
}
diff --git a/libavformat/isom.c b/libavformat/isom.c
index f669e0e923..ae10cb7d3f 100644
--- a/libavformat/isom.c
+++ b/libavformat/isom.c
@@ -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') },
diff --git a/libavformat/riff.c b/libavformat/riff.c
index 3c5a37c3f6..e4e394d613 100644
--- a/libavformat/riff.c
+++ b/libavformat/riff.c
@@ -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 }