312 lines · 13.6 KB · C
RawDownload
/* * Copyright © 2018, VideoLAN and dav1d authors * Copyright © 2018, Two Orioles, LLC * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this *    list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, *    this list of conditions and the following disclaimer in the documentation *    and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #ifndef __plan9__#include <stdio.h>#endif #include "common/intops.h" #include "src/lr_apply.h" enum LrRestorePlanes {    LR_RESTORE_Y = 1 << 0,    LR_RESTORE_U = 1 << 1,    LR_RESTORE_V = 1 << 2,}; // The loop filter buffer stores 12 rows of pixels. A superblock block will// contain at most 2 stripes. Each stripe requires 4 rows pixels (2 above// and 2 below) the final 4 rows are used to swap the bottom of the last// stripe with the top of the next super block row.static void backup_lpf(const Dav1dFrameContext *const f,                       pixel *dst, const ptrdiff_t dst_stride,                       const pixel *src, const ptrdiff_t src_stride,                       const int ss_ver, const int sb128,                       int row, const int row_h, const int src_w,                       const int h, const int ss_hor){    const int dst_w = f->frame_hdr->super_res.enabled ?                      (f->frame_hdr->width[1] + ss_hor) >> ss_hor : src_w;     // The first stripe of the frame is shorter by 8 luma pixel rows.    int stripe_h = (64 - 8 * !row) >> ss_ver;     if (row) {        const int top = 4 << sb128;        // Copy the top part of the stored loop filtered pixels from the        // previous sb row needed above the first stripe of this sb row.        pixel_copy(&dst[PXSTRIDE(dst_stride) *  0],                   &dst[PXSTRIDE(dst_stride) *  top],      dst_w);        pixel_copy(&dst[PXSTRIDE(dst_stride) *  1],                   &dst[PXSTRIDE(dst_stride) * (top + 1)], dst_w);        pixel_copy(&dst[PXSTRIDE(dst_stride) *  2],                   &dst[PXSTRIDE(dst_stride) * (top + 2)], dst_w);        pixel_copy(&dst[PXSTRIDE(dst_stride) *  3],                   &dst[PXSTRIDE(dst_stride) * (top + 3)], dst_w);    }     dst += 4 * PXSTRIDE(dst_stride);    src += (stripe_h - 2) * PXSTRIDE(src_stride);     if (f->frame_hdr->width[0] != f->frame_hdr->width[1]) {        while (row + stripe_h <= row_h) {            const int n_lines = 4 - (row + stripe_h + 1 == h);            f->dsp->mc.resize(dst, dst_stride, src, src_stride,                              dst_w, n_lines, src_w, f->resize_step[ss_hor],                              f->resize_start[ss_hor] HIGHBD_CALL_SUFFIX);            row += stripe_h; // unmodified stripe_h for the 1st stripe            stripe_h = 64 >> ss_ver;            src += stripe_h * PXSTRIDE(src_stride);            dst += n_lines * PXSTRIDE(dst_stride);            if (n_lines == 3) {                pixel_copy(dst, &dst[-PXSTRIDE(dst_stride)], dst_w);                dst += PXSTRIDE(dst_stride);            }        }    } else {        while (row + stripe_h <= row_h) {            const int n_lines = 4 - (row + stripe_h + 1 == h);            for (int i = 0; i < 4; i++) {                pixel_copy(dst, i == n_lines ? &dst[-PXSTRIDE(dst_stride)] :                                               src, src_w);                dst += PXSTRIDE(dst_stride);                src += PXSTRIDE(src_stride);            }            row += stripe_h; // unmodified stripe_h for the 1st stripe            stripe_h = 64 >> ss_ver;            src += (stripe_h - 4) * PXSTRIDE(src_stride);        }    }} void bytefn(dav1d_lr_copy_lpf)(Dav1dFrameContext *const f,                               /*const*/ pixel *const src[3], const int sby){    const int offset = 8 * !!sby;    const ptrdiff_t *const src_stride = f->cur.stride;    const ptrdiff_t lr_stride = ((f->sr_cur.p.p.w + 31) & ~31) * sizeof(pixel);     // TODO Also check block level restore type to reduce copying.    const int restore_planes = f->lf.restore_planes;     if (restore_planes & LR_RESTORE_Y) {        const int h = f->cur.p.h;        const int w = f->bw << 2;        const int row_h = imin((sby + 1) << (6 + f->seq_hdr->sb128), h - 1);        const int y_stripe = (sby << (6 + f->seq_hdr->sb128)) - offset;        backup_lpf(f, f->lf.lr_lpf_line[0], lr_stride,                   src[0] - offset * PXSTRIDE(src_stride[0]), src_stride[0],                   0, f->seq_hdr->sb128, y_stripe, row_h, w, h, 0);    }    if (restore_planes & (LR_RESTORE_U | LR_RESTORE_V)) {        const int ss_ver = f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420;        const int ss_hor = f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444;        const int h = (f->cur.p.h + ss_ver) >> ss_ver;        const int w = f->bw << (2 - ss_hor);        const int row_h = imin((sby + 1) << ((6 - ss_ver) + f->seq_hdr->sb128), h - 1);        const int offset_uv = offset >> ss_ver;        const int y_stripe =            (sby << ((6 - ss_ver) + f->seq_hdr->sb128)) - offset_uv;         if (restore_planes & LR_RESTORE_U) {            backup_lpf(f, f->lf.lr_lpf_line[1], lr_stride,                       src[1] - offset_uv * PXSTRIDE(src_stride[1]), src_stride[1],                       ss_ver, f->seq_hdr->sb128, y_stripe, row_h, w, h, ss_hor);        }        if (restore_planes & LR_RESTORE_V) {            backup_lpf(f, f->lf.lr_lpf_line[2], lr_stride,                       src[2] - offset_uv * PXSTRIDE(src_stride[1]), src_stride[1],                       ss_ver, f->seq_hdr->sb128, y_stripe, row_h, w, h, ss_hor);        }    }} static void lr_stripe(const Dav1dFrameContext *const f, pixel *p,                      const pixel (*left)[4], int x, int y,                      const int plane, const int unit_w, const int row_h,                      const Av1RestorationUnit *const lr, enum LrEdgeFlags edges){    const Dav1dDSPContext *const dsp = f->dsp;    const int chroma = !!plane;    const int ss_ver = chroma & (f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420);    const int sbrow_has_bottom = (edges & LR_HAVE_BOTTOM);    const pixel *lpf = f->lf.lr_lpf_line[plane] + x;    const ptrdiff_t p_stride = f->sr_cur.p.stride[chroma];    const ptrdiff_t lpf_stride = sizeof(pixel) * ((f->sr_cur.p.p.w + 31) & ~31);     // The first stripe of the frame is shorter by 8 luma pixel rows.    int stripe_h = imin((64 - 8 * !y) >> ss_ver, row_h - y);     ALIGN_STK_16(int16_t, filter, 2, [8]);    wienerfilter_fn wiener_fn = NULL;    if (lr->type == DAV1D_RESTORATION_WIENER) {        filter[0][0] = filter[0][6] = lr->filter_h[0];        filter[0][1] = filter[0][5] = lr->filter_h[1];        filter[0][2] = filter[0][4] = lr->filter_h[2];        filter[0][3] = -(filter[0][0] + filter[0][1] + filter[0][2]) * 2;#if BITDEPTH != 8        /* For 8-bit SIMD it's beneficial to handle the +128 separately         * in order to avoid overflows. */        filter[0][3] += 128;#endif         filter[1][0] = filter[1][6] = lr->filter_v[0];        filter[1][1] = filter[1][5] = lr->filter_v[1];        filter[1][2] = filter[1][4] = lr->filter_v[2];        filter[1][3] = 128 - (filter[1][0] + filter[1][1] + filter[1][2]) * 2;         wiener_fn = dsp->lr.wiener[!(filter[0][0] | filter[1][0])];    } else {        assert(lr->type == DAV1D_RESTORATION_SGRPROJ);    }     while (y + stripe_h <= row_h) {        // Change HAVE_BOTTOM bit in edges to (y + stripe_h != row_h)        edges ^= (-(y + stripe_h != row_h) ^ edges) & LR_HAVE_BOTTOM;        if (wiener_fn) {            wiener_fn(p, p_stride, left, lpf, lpf_stride, unit_w, stripe_h,                      filter, edges HIGHBD_CALL_SUFFIX);        } else {            dsp->lr.selfguided(p, p_stride, left, lpf, lpf_stride, unit_w, stripe_h,                               lr->sgr_idx, lr->sgr_weights, edges HIGHBD_CALL_SUFFIX);        }         left += stripe_h;        y += stripe_h;        if (y + stripe_h > row_h && sbrow_has_bottom) break;        p += stripe_h * PXSTRIDE(p_stride);        edges |= LR_HAVE_TOP;        stripe_h = imin(64 >> ss_ver, row_h - y);        if (stripe_h == 0) break;        lpf += 4 * PXSTRIDE(lpf_stride);    }} static void backup4xU(pixel (*dst)[4], const pixel *src, const ptrdiff_t src_stride,                      int u){    for (; u > 0; u--, dst++, src += PXSTRIDE(src_stride))        pixel_copy(dst, src, 4);} static void lr_sbrow(const Dav1dFrameContext *const f, pixel *p, const int y,                     const int w, const int h, const int row_h, const int plane){    const int chroma = !!plane;    const int ss_ver = chroma & (f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420);    const int ss_hor = chroma & (f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444);    const ptrdiff_t p_stride = f->sr_cur.p.stride[chroma];     const int unit_size_log2 = f->frame_hdr->restoration.unit_size[!!plane];    const int unit_size = 1 << unit_size_log2;    const int half_unit_size = unit_size >> 1;    const int max_unit_size = unit_size + half_unit_size;     // Y coordinate of the sbrow (y is 8 luma pixel rows above row_y)    const int row_y = y + ((8 >> ss_ver) * !!y);     // FIXME This is an ugly hack to lookup the proper AV1Filter unit for    // chroma planes. Question: For Multithreaded decoding, is it better    // to store the chroma LR information with collocated Luma information?    // In other words. For a chroma restoration unit locate at 128,128 and    // with a 4:2:0 chroma subsampling, do we store the filter information at    // the AV1Filter unit located at (128,128) or (256,256)    // TODO Support chroma subsampling.    const int shift_hor = 7 - ss_hor;     pixel pre_lr_border[2][128 + 8 /* maximum sbrow height is 128 + 8 rows offset */][4];    const Av1RestorationUnit *lr[2];     enum LrEdgeFlags edges = (y > 0 ? LR_HAVE_TOP : 0) | LR_HAVE_RIGHT |                             (row_h < h ? LR_HAVE_BOTTOM : 0);     int aligned_unit_pos = row_y & ~(unit_size - 1);    if (aligned_unit_pos && aligned_unit_pos + half_unit_size > h)        aligned_unit_pos -= unit_size;    aligned_unit_pos <<= ss_ver;    const int sb_idx = (aligned_unit_pos >> 7) * f->sr_sb128w;    const int unit_idx = ((aligned_unit_pos >> 6) & 1) << 1;    lr[0] = &f->lf.lr_mask[sb_idx].lr[plane][unit_idx];    int restore = lr[0]->type != DAV1D_RESTORATION_NONE;    int x = 0, bit = 0;    for (; x + max_unit_size <= w; p += unit_size, edges |= LR_HAVE_LEFT, bit ^= 1) {        const int next_x = x + unit_size;        const int next_u_idx = unit_idx + ((next_x >> (shift_hor - 1)) & 1);        lr[!bit] =            &f->lf.lr_mask[sb_idx + (next_x >> shift_hor)].lr[plane][next_u_idx];        const int restore_next = lr[!bit]->type != DAV1D_RESTORATION_NONE;        if (restore_next)            backup4xU(pre_lr_border[bit], p + unit_size - 4, p_stride, row_h - y);        if (restore)            lr_stripe(f, p, pre_lr_border[!bit], x, y, plane, unit_size, row_h,                      lr[bit], edges);        x = next_x;        restore = restore_next;    }    if (restore) {        edges &= ~LR_HAVE_RIGHT;        const int unit_w = w - x;        lr_stripe(f, p, pre_lr_border[!bit], x, y, plane, unit_w, row_h, lr[bit], edges);    }} void bytefn(dav1d_lr_sbrow)(Dav1dFrameContext *const f, pixel *const dst[3],                            const int sby){    const int offset_y = 8 * !!sby;    const ptrdiff_t *const dst_stride = f->sr_cur.p.stride;    const int restore_planes = f->lf.restore_planes;     if (restore_planes & LR_RESTORE_Y) {        const int h = f->sr_cur.p.p.h;        const int w = f->sr_cur.p.p.w;        const int row_h = imin((sby + 1) << (6 + f->seq_hdr->sb128), h);        const int y_stripe = (sby << (6 + f->seq_hdr->sb128)) - offset_y;        lr_sbrow(f, dst[0] - offset_y * PXSTRIDE(dst_stride[0]), y_stripe, w,                 h, row_h, 0);    }    if (restore_planes & (LR_RESTORE_U | LR_RESTORE_V)) {        const int ss_ver = f->sr_cur.p.p.layout == DAV1D_PIXEL_LAYOUT_I420;        const int ss_hor = f->sr_cur.p.p.layout != DAV1D_PIXEL_LAYOUT_I444;        const int h = (f->sr_cur.p.p.h + ss_ver) >> ss_ver;        const int w = (f->sr_cur.p.p.w + ss_hor) >> ss_hor;        const int row_h = imin((sby + 1) << ((6 - ss_ver) + f->seq_hdr->sb128), h);        const int offset_uv = offset_y >> ss_ver;        const int y_stripe =            (sby << ((6 - ss_ver) + f->seq_hdr->sb128)) - offset_uv;        if (restore_planes & LR_RESTORE_U)            lr_sbrow(f, dst[1] - offset_uv * PXSTRIDE(dst_stride[1]), y_stripe,                     w, h, row_h, 1);         if (restore_planes & LR_RESTORE_V)            lr_sbrow(f, dst[2] - offset_uv * PXSTRIDE(dst_stride[1]), y_stripe,                     w, h, row_h, 2);    }}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t