utvideodec: Support for gradient prediction
authorPaul B Mahol <onemda@gmail.com>
Fri, 7 Apr 2017 18:09:22 +0000 (20:09 +0200)
committerLuca Barbato <lu_zero@gentoo.org>
Sat, 15 Apr 2017 13:37:18 +0000 (15:37 +0200)
Introduced with utvideo 18.

Signed-off-by: Paul B Mahol <onemda@gmail.com>
Signed-off-by: Luca Barbato <lu_zero@gentoo.org>
libavcodec/utvideodec.c

index 67ffe6f..910d64b 100644 (file)
@@ -602,6 +602,189 @@ static void restore_median_packed_il(uint8_t *src, int step, ptrdiff_t stride,
     }
 }
 
+static void restore_gradient_planar(UtvideoContext *c, uint8_t *src, ptrdiff_t stride,
+                                    int width, int height, int slices, int rmode)
+{
+    int i, j, slice;
+    int A, B, C;
+    uint8_t *bsrc;
+    int slice_start, slice_height;
+    const int cmask = ~rmode;
+
+    for (slice = 0; slice < slices; slice++) {
+        slice_start  = ((slice * height) / slices) & cmask;
+        slice_height = ((((slice + 1) * height) / slices) & cmask) -
+                       slice_start;
+
+        if (!slice_height)
+            continue;
+        bsrc = src + slice_start * stride;
+
+        // first line - left neighbour prediction
+        bsrc[0] += 0x80;
+        c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+        bsrc += stride;
+        if (slice_height <= 1)
+            continue;
+        for (j = 1; j < slice_height; j++) {
+            // second line - first element has top prediction, the rest uses gradient
+            bsrc[0] = (bsrc[0] + bsrc[-stride]) & 0xFF;
+            for (i = 1; i < width; i++) {
+                A = bsrc[i - stride];
+                B = bsrc[i - (stride + 1)];
+                C = bsrc[i - 1];
+                bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+            }
+            bsrc += stride;
+        }
+    }
+}
+
+static void restore_gradient_planar_il(UtvideoContext *c, uint8_t *src, ptrdiff_t stride,
+                                      int width, int height, int slices, int rmode)
+{
+    int i, j, slice;
+    int A, B, C;
+    uint8_t *bsrc;
+    int slice_start, slice_height;
+    const int cmask   = ~(rmode ? 3 : 1);
+    const ptrdiff_t stride2 = stride << 1;
+
+    for (slice = 0; slice < slices; slice++) {
+        slice_start    = ((slice * height) / slices) & cmask;
+        slice_height   = ((((slice + 1) * height) / slices) & cmask) -
+                         slice_start;
+        slice_height >>= 1;
+        if (!slice_height)
+            continue;
+
+        bsrc = src + slice_start * stride;
+
+        // first line - left neighbour prediction
+        bsrc[0] += 0x80;
+        A = c->hdspdec.add_hfyu_left_pred(bsrc, bsrc, width, 0);
+        c->hdspdec.add_hfyu_left_pred(bsrc + stride, bsrc + stride, width, A);
+        bsrc += stride2;
+        if (slice_height <= 1)
+            continue;
+        for (j = 1; j < slice_height; j++) {
+            // second line - first element has top prediction, the rest uses gradient
+            bsrc[0] = (bsrc[0] + bsrc[-stride2]) & 0xFF;
+            for (i = 1; i < width; i++) {
+                A = bsrc[i - stride2];
+                B = bsrc[i - (stride2 + 1)];
+                C = bsrc[i - 1];
+                bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+            }
+            for (i = 0; i < width; i++) {
+                A = bsrc[i - stride];
+                B = bsrc[i - (1 + stride)];
+                C = bsrc[i - 1 + stride];
+                bsrc[i + stride] = (A - B + C + bsrc[i + stride]) & 0xFF;
+            }
+            bsrc += stride2;
+        }
+    }
+}
+
+static void restore_gradient_packed(uint8_t *src, int step, ptrdiff_t stride,
+                                    int width, int height, int slices, int rmode)
+{
+    int i, j, slice;
+    int A, B, C;
+    uint8_t *bsrc;
+    int slice_start, slice_height;
+    const int cmask = ~rmode;
+
+    for (slice = 0; slice < slices; slice++) {
+        slice_start  = ((slice * height) / slices) & cmask;
+        slice_height = ((((slice + 1) * height) / slices) & cmask) -
+                       slice_start;
+
+        if (!slice_height)
+            continue;
+        bsrc = src + slice_start * stride;
+
+        // first line - left neighbour prediction
+        bsrc[0] += 0x80;
+        A = bsrc[0];
+        for (i = step; i < width * step; i += step) {
+            bsrc[i] += A;
+            A        = bsrc[i];
+        }
+        bsrc += stride;
+        if (slice_height <= 1)
+            continue;
+        for (j = 1; j < slice_height; j++) {
+            // second line - first element has top prediction, the rest uses gradient
+            C        = bsrc[-stride];
+            bsrc[0] += C;
+            for (i = step; i < width * step; i += step) {
+                A = bsrc[i - stride];
+                B = bsrc[i - (stride + step)];
+                C = bsrc[i - step];
+                bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+            }
+            bsrc += stride;
+        }
+    }
+}
+
+static void restore_gradient_packed_il(uint8_t *src, int step, ptrdiff_t stride,
+                                       int width, int height, int slices, int rmode)
+{
+    int i, j, slice;
+    int A, B, C;
+    uint8_t *bsrc;
+    int slice_start, slice_height;
+    const int cmask   = ~(rmode ? 3 : 1);
+    const ptrdiff_t stride2 = stride << 1;
+
+    for (slice = 0; slice < slices; slice++) {
+        slice_start    = ((slice * height) / slices) & cmask;
+        slice_height   = ((((slice + 1) * height) / slices) & cmask) -
+                         slice_start;
+        slice_height >>= 1;
+        if (!slice_height)
+            continue;
+
+        bsrc = src + slice_start * stride;
+
+        // first line - left neighbour prediction
+        bsrc[0] += 0x80;
+        A        = bsrc[0];
+        for (i = step; i < width * step; i += step) {
+            bsrc[i] += A;
+            A        = bsrc[i];
+        }
+        for (i = 0; i < width * step; i += step) {
+            bsrc[stride + i] += A;
+            A                 = bsrc[stride + i];
+        }
+        bsrc += stride2;
+        if (slice_height <= 1)
+            continue;
+        for (j = 1; j < slice_height; j++) {
+            // second line - first element has top prediction, the rest uses gradient
+            C        = bsrc[-stride2];
+            bsrc[0] += C;
+            for (i = step; i < width * step; i += step) {
+                A = bsrc[i - stride2];
+                B = bsrc[i - (stride2 + step)];
+                C = bsrc[i - step];
+                bsrc[i] = (A - B + C + bsrc[i]) & 0xFF;
+            }
+            for (i = 0; i < width * step; i += step) {
+                A = bsrc[i - stride];
+                B = bsrc[i - (step + stride)];
+                C = bsrc[i - step + stride];
+                bsrc[i + stride] = (A - B + C + bsrc[i + stride]) & 0xFF;
+            }
+            bsrc += stride2;
+        }
+    }
+}
+
 static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
                         AVPacket *avpkt)
 {
@@ -691,11 +874,6 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
 
     c->frame_pred = (c->frame_info >> 8) & 3;
 
-    if (c->frame_pred == PRED_GRADIENT) {
-        avpriv_request_sample(avctx, "Frame with gradient prediction");
-        return AVERROR_PATCHWELCOME;
-    }
-
     av_fast_malloc(&c->slice_bits, &c->slice_bits_size,
                    max_slice_size + AV_INPUT_BUFFER_PADDING_SIZE);
 
@@ -725,6 +903,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
                                              avctx->width, avctx->height, c->slices,
                                              0);
                 }
+            } else if (c->frame_pred == PRED_GRADIENT) {
+                if (!c->interlaced) {
+                    restore_gradient_packed(frame.f->data[0] + ff_ut_rgb_order[i],
+                                            c->planes, frame.f->linesize[0],
+                                            avctx->width, avctx->height,
+                                            c->slices, 0);
+                } else {
+                    restore_gradient_packed_il(frame.f->data[0] + ff_ut_rgb_order[i],
+                                               c->planes, frame.f->linesize[0],
+                                               avctx->width, avctx->height,
+                                               c->slices, 0);
+                }
             }
         }
         restore_rgb_planes(frame.f->data[0], c->planes, frame.f->linesize[0],
@@ -761,6 +951,18 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
                                              avctx->height >> !!i,
                                              c->slices, !i);
                 }
+            } else if (c->frame_pred == PRED_GRADIENT) {
+                if (!c->interlaced) {
+                    restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i],
+                                            avctx->width >> !!i,
+                                            avctx->height >> !!i,
+                                            c->slices, !i);
+                } else {
+                    restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+                                               avctx->width  >> !!i,
+                                               avctx->height >> !!i,
+                                               c->slices, !i);
+                }
             }
         }
         break;
@@ -781,6 +983,16 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
                                              avctx->width >> !!i, avctx->height,
                                              c->slices, 0);
                 }
+            } else if (c->frame_pred == PRED_GRADIENT) {
+                if (!c->interlaced) {
+                    restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i],
+                                            avctx->width >> !!i, avctx->height,
+                                            c->slices, 0);
+                } else {
+                    restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+                                               avctx->width  >> !!i, avctx->height,
+                                               c->slices, 0);
+                }
             }
         }
         break;
@@ -801,6 +1013,16 @@ static int decode_frame(AVCodecContext *avctx, void *data, int *got_frame,
                                              avctx->width, avctx->height,
                                              c->slices, 0);
                 }
+            } else if (c->frame_pred == PRED_GRADIENT) {
+                if (!c->interlaced) {
+                    restore_gradient_planar(c, frame.f->data[i], frame.f->linesize[i],
+                                            avctx->width, avctx->height,
+                                            c->slices, 0);
+                } else {
+                    restore_gradient_planar_il(c, frame.f->data[i], frame.f->linesize[i],
+                                               avctx->width, avctx->height,
+                                               c->slices, 0);
+                }
             }
         }
         break;