]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/magicyuv.c
avfilter/vf_midequalizer: Remove duplicate include
[ffmpeg] / libavcodec / magicyuv.c
index 2c312bec17063f86dae62a5236ac1689a7418bbd..6250536da6168f1514902dfd0e38d066a8b9888f 100644 (file)
@@ -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,26 +45,32 @@ 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
     int               decorrelate;    // postprocessing work
+    int               color_matrix;   // video color matrix
+    int               flags;
     int               interlaced;     // video is interlaced
     uint8_t          *buf;            // pointer to AVPacket->data
     int               hshift[4];
     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
-    HuffYUVDSPContext hdsp;
+    int (*huff_build)(VLC *vlc, uint8_t *len);
+    int (*magy_decode_slice)(AVCodecContext *avctx, void *tdata,
+                             int j, int threadnr);
+    LLVidDSPContext   llviddsp;
 } MagicYUVContext;
 
 static int huff_cmp_len(const void *a, const void *b)
@@ -72,6 +79,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 +145,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_left_pred_int16(dst, dst, 1023, width, 0);
+            dst += stride;
+            if (interlaced) {
+                s->llviddsp.add_left_pred_int16(dst, dst, 1023, width, 0);
+                dst += stride;
+            }
+            for (k = 1 + interlaced; k < height; k++) {
+                s->llviddsp.add_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_left_pred_int16(dst, dst, 1023, width, 0);
+            left = lefttop = 0;
+            dst += stride;
+            if (interlaced) {
+                s->llviddsp.add_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_left_pred_int16(dst, dst, 1023, width, 0);
+            dst += stride;
+            if (interlaced) {
+                lefttop = left = dst[0];
+                s->llviddsp.add_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)
 {
@@ -157,24 +352,24 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata,
         switch (pred) {
         case LEFT:
             dst = p->data[i] + j * sheight * stride;
-            s->hdsp.add_hfyu_left_pred(dst, dst, width, 0);
+            s->llviddsp.add_left_pred(dst, dst, width, 0);
             dst += stride;
             if (interlaced) {
-                s->hdsp.add_hfyu_left_pred(dst, dst, width, 0);
+                s->llviddsp.add_left_pred(dst, dst, width, 0);
                 dst += stride;
             }
             for (k = 1 + interlaced; k < height; k++) {
-                s->hdsp.add_hfyu_left_pred(dst, dst, width, dst[-fake_stride]);
+                s->llviddsp.add_left_pred(dst, dst, width, dst[-fake_stride]);
                 dst += stride;
             }
             break;
         case GRADIENT:
             dst = p->data[i] + j * sheight * stride;
-            s->hdsp.add_hfyu_left_pred(dst, dst, width, 0);
+            s->llviddsp.add_left_pred(dst, dst, width, 0);
             left = lefttop = 0;
             dst += stride;
             if (interlaced) {
-                s->hdsp.add_hfyu_left_pred(dst, dst, width, 0);
+                s->llviddsp.add_left_pred(dst, dst, width, 0);
                 left = lefttop = 0;
                 dst += stride;
             }
@@ -194,15 +389,15 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata,
         case MEDIAN:
             dst = p->data[i] + j * sheight * stride;
             lefttop = left = dst[0];
-            s->hdsp.add_hfyu_left_pred(dst, dst, width, 0);
+            s->llviddsp.add_left_pred(dst, dst, width, 0);
             dst += stride;
             if (interlaced) {
                 lefttop = left = dst[0];
-                s->hdsp.add_hfyu_left_pred(dst, dst, width, 0);
+                s->llviddsp.add_left_pred(dst, dst, width, 0);
                 dst += stride;
             }
             for (k = 1 + interlaced; k < height; k++) {
-                s->hdsp.add_hfyu_median_pred(dst, dst - fake_stride,
+                s->llviddsp.add_median_pred(dst, dst - fake_stride,
                                              dst, width, &left, &lefttop);
                 lefttop = left = dst[0];
                 dst += stride;
@@ -221,8 +416,8 @@ static int magy_decode_slice(AVCodecContext *avctx, void *tdata,
         uint8_t *r = p->data[2] + j * s->slice_height * p->linesize[2];
 
         for (i = 0; i < height; i++) {
-            s->hdsp.add_bytes(b, g, width);
-            s->hdsp.add_bytes(r, g, width);
+            s->llviddsp.add_bytes(b, g, width);
+            s->llviddsp.add_bytes(r, g, width);
             b += p->linesize[0];
             g += p->linesize[1];
             r += p->linesize[2];
@@ -232,6 +427,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 +476,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 +500,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,14 +535,44 @@ 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;
     }
     s->planes = av_pix_fmt_count_planes(avctx->pix_fmt);
 
-    bytestream2_skip(&gbyte, 2);
-    s->interlaced = !!(bytestream2_get_byte(&gbyte) & 2);
+    bytestream2_skip(&gbyte, 1);
+    s->color_matrix = bytestream2_get_byte(&gbyte);
+    s->flags        = bytestream2_get_byte(&gbyte);
+    s->interlaced   = !!(s->flags & 2);
     bytestream2_skip(&gbyte, 3);
 
     width  = bytestream2_get_le32(&gbyte);
@@ -375,37 +642,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,12 +654,24 @@ 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]);
+    } else {
+        switch (s->color_matrix) {
+        case 1:
+            p->colorspace = AVCOL_SPC_BT470BG;
+            break;
+        case 2:
+            p->colorspace = AVCOL_SPC_BT709;
+            break;
+        }
+        p->color_range = (s->flags & 4) ? AVCOL_RANGE_JPEG : AVCOL_RANGE_MPEG;
     }
 
     *got_frame = 1;
@@ -446,7 +697,7 @@ static int magy_init_thread_copy(AVCodecContext *avctx)
 static av_cold int magy_decode_init(AVCodecContext *avctx)
 {
     MagicYUVContext *s = avctx->priv_data;
-    ff_huffyuvdsp_init(&s->hdsp);
+    ff_llviddsp_init(&s->llviddsp);
     return 0;
 }