[FFmpeg-cvslog] avcodec/magicyuv: add 10 bit support

Paul B Mahol git at videolan.org
Tue Dec 20 14:32:33 EET 2016


ffmpeg | branch: master | Paul B Mahol <onemda at gmail.com> | Mon Dec 19 23:21:49 2016 +0100| [6d09d6edbc464454a620e3ecf64fe752b5cfa9cc] | committer: Paul B Mahol

avcodec/magicyuv: add 10 bit support

Signed-off-by: Paul B Mahol <onemda at gmail.com>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=6d09d6edbc464454a620e3ecf64fe752b5cfa9cc
---

 configure                               |   2 +-
 libavcodec/magicyuv.c                   | 313 ++++++++++++++++++++++++++++----
 libavcodec/x86/lossless_videodsp_init.c |   2 +-
 libavformat/isom.c                      |   4 +
 libavformat/riff.c                      |   4 +
 5 files changed, 286 insertions(+), 39 deletions(-)

diff --git a/configure b/configure
index 9dfd006..e2e171e 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 2c312be..16d7027 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 b0fbcfe..548d043 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 f669e0e..ae10cb7 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 3c5a37c..e4e394d 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 }



More information about the ffmpeg-cvslog mailing list