From patchwork Mon Apr 23 18:58:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Borsboom X-Patchwork-Id: 8608 Delivered-To: ffmpegpatchwork@gmail.com Received: by 2002:a02:155:0:0:0:0:0 with SMTP id c82-v6csp1019520jad; Mon, 23 Apr 2018 11:59:01 -0700 (PDT) X-Google-Smtp-Source: AB8JxZq/bzP4wiEKJ9k5h/8bawfjpWmYwKknZ+yb1TPP2qCOzakHOLJgalA2j2XvfMOM9WuYDZ9z X-Received: by 10.28.212.210 with SMTP id l201mr9827076wmg.98.1524509941785; Mon, 23 Apr 2018 11:59:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1524509941; cv=none; d=google.com; s=arc-20160816; b=ytd4fSrvRppO9wQpG2jMIhSfzVYFVQ+oablvWoPSCEYm64LsaIBUuwtq5IeSGoawQl 2l8+TRM3R9u+Ni5fHpXOmHBftBaAp6DtKPmoTim0EP5RrnzlkHfTITN8JAWHsDqyhiu8 LwsbrI2H2pmIt+RsW5PoRDQfAQuXft+LCfYf5W016oXaHFLvCIwDt6WJVEpIKM6Mc9mO 3Sgei4lLMb3t6Yk3Z7oV2CzeYKtXdy4WsY0/skoALHz+986NU+g5Y9eiprhON3bicIfB 4iKrT+4O3K0dl+qjF4l27fEaSGIZdTGC/DObJ1ge7UA/QgLmdeRjf2+zcGXB8WGAlWyU buzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:content-language:mime-version:user-agent:date :message-id:from:to:dkim-signature:delivered-to :arc-authentication-results; bh=UQR8nAr2PqWOjqKlsvp6mMic7phZ91QRVfsuF5flyG0=; b=TufXt0AYb3TA5cp9C561sGeaVE69ZXJRsGXWgSfZA2ef1RfOrI7p8oHTJbAWGy1QzB 1s8EVmBrtN0qVjkqImaFvqhwksxpxT8xmunqydJ+YGbf6p8e46wTOXVWpzXYSbnsgCDW Ji7PntdycqqraHED4L2lQIoMnACdtECOeiibdNap/vanjf42hxtMiQAYUZF6AV3/ENfw gFFMp1U9tVyUIfeVzgJ70SnOxe3epQsJwwEh7YZF/JNSVaMQ2KScCYCoeF96E06u7s3f Q2aWF/hZYBb3DkIZea/n74UUjGWlbC6QKQN1ujvjK9iVkowkQL7Fxtis5Vd186vuP9pD +ayA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@carpalis.nl header.s=default header.b=Tu+NQgBj; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id j4-v6si10191681wrg.449.2018.04.23.11.59.01; Mon, 23 Apr 2018 11:59:01 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@carpalis.nl header.s=default header.b=Tu+NQgBj; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 81EDB68A042; Mon, 23 Apr 2018 21:58:30 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from kyoto.xs4all.nl (kyoto.xs4all.nl [83.161.153.34]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 28AAF6805C3 for ; Mon, 23 Apr 2018 21:58:24 +0300 (EEST) Received: from [IPv6:2001:980:9507:0:8e70:5aff:fec6:83fc] ([IPv6:2001:980:9507:0:8e70:5aff:fec6:83fc]) (authenticated bits=0) by kyoto.xs4all.nl (8.14.7/8.14.7) with ESMTP id w3NIwqEW003279 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Mon, 23 Apr 2018 20:58:52 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=carpalis.nl; s=default; t=1524509932; bh=hlW+sc6BESdoL8N66r0MfvBeSnQB0SIFaZDpblK8ot8=; h=To:From:Subject:Date; b=Tu+NQgBjtIBHSb9m8bjsobejs6o94f2nWSigQNOgUdc8AWj0f+Hgnrxbw/IXGMtLa N33rxQYvQyHJZTHYodxK66PLxr/PNYyPywSfXXg7zQRK0TUVHf0pI9yvXf6MIZ2O+4 5uMnDFmhW2/SVgGEZgwBXKswZISi8vRwFIAMkqn/Whb3rSQEyir6LVF2Mpbl2ln4Dd hTWkart1OiokvboNwIN7UCT6fZJiB9los7jIONZ83fQ3Jl57+3knt+xIENos7/3xb2 yCAfZ1bwYql/8/Yakfr2PKEmSvhiNHlZNZ+iVTleRr1rFiH5vLoYWc8fggH3AE912f XluhT2+tL1SxQ== To: ffmpeg-devel@ffmpeg.org From: Jerome Borsboom Message-ID: Date: Mon, 23 Apr 2018 20:58:52 +0200 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:52.0) Gecko/20100101 Thunderbird/52.7.0 MIME-Version: 1.0 Content-Language: nl Subject: [FFmpeg-devel] [PATCH 03/14] avcodec/vc1: re-implement and expand VC-1 loop filtering X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" The existing implementation did loop filtering for progressive frames only. This rewritten version implements loop filtering for all applicable frame types for both progessive and frame/field-interlace. Signed-off-by: Jerome Borsboom --- libavcodec/vc1.h | 4 + libavcodec/vc1_loopfilter.c | 1042 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1046 insertions(+) diff --git a/libavcodec/vc1.h b/libavcodec/vc1.h index 85504c2f9f..0dfdef78cd 100644 --- a/libavcodec/vc1.h +++ b/libavcodec/vc1.h @@ -428,6 +428,10 @@ void ff_vc1_smooth_overlap_filter_iblk(VC1Context *v); void ff_vc1_i_overlap_filter(VC1Context *v); void ff_vc1_p_overlap_filter(VC1Context *v); void ff_vc1_apply_p_loop_filter(VC1Context *v); +void ff_vc1_i_loop_filter(VC1Context *v); +void ff_vc1_p_loop_filter(VC1Context *v); +void ff_vc1_p_intfr_loop_filter(VC1Context *v); +void ff_vc1_b_intfi_loop_filter(VC1Context *v); void ff_vc1_mc_1mv(VC1Context *v, int dir); void ff_vc1_mc_4mv_luma(VC1Context *v, int n, int dir, int avg); diff --git a/libavcodec/vc1_loopfilter.c b/libavcodec/vc1_loopfilter.c index 3122b1a258..7ef0fd1ea2 100644 --- a/libavcodec/vc1_loopfilter.c +++ b/libavcodec/vc1_loopfilter.c @@ -451,3 +451,1045 @@ void ff_vc1_apply_p_loop_filter(VC1Context *v) } } } + +#define LEFT_EDGE (1 << 0) +#define RIGHT_EDGE (1 << 1) +#define TOP_EDGE (1 << 2) +#define BOTTOM_EDGE (1 << 3) + +static av_always_inline void vc1_i_h_loop_filter(VC1Context *v, uint8_t *dest, + uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + + if (block_num & 2) + return; + + if (!(flags & LEFT_EDGE) || (block_num & 5) == 1) { + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (v->fcm == ILACE_FRAME) + if (block_num > 3) { + v->vc1dsp.vc1_h_loop_filter4(dst, 2 * s->uvlinesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + s->uvlinesize, 2 * s->uvlinesize, pq); + } else { + v->vc1dsp.vc1_h_loop_filter8(dst, 2 * s->linesize, pq); + v->vc1dsp.vc1_h_loop_filter8(dst + s->linesize, 2 * s->linesize, pq); + } + else + if (block_num > 3) + v->vc1dsp.vc1_h_loop_filter8(dst, s->uvlinesize, pq); + else + v->vc1dsp.vc1_h_loop_filter16(dst, s->linesize, pq); + } +} + +static av_always_inline void vc1_i_v_loop_filter(VC1Context *v, uint8_t *dest, + uint32_t flags, uint8_t fieldtx, + int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + + if ((block_num & 5) == 1) + return; + + if (!(flags & TOP_EDGE) || block_num & 2) { + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (v->fcm == ILACE_FRAME) { + if (block_num > 3) { + v->vc1dsp.vc1_v_loop_filter8(dst, 2 * s->uvlinesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + s->uvlinesize, 2 * s->uvlinesize, pq); + } else if (block_num < 2 || !fieldtx) { + v->vc1dsp.vc1_v_loop_filter16(dst, 2 * s->linesize, pq); + v->vc1dsp.vc1_v_loop_filter16(dst + s->linesize, 2 * s->linesize, pq); + } + } else + if (block_num > 3) + v->vc1dsp.vc1_v_loop_filter8(dst, s->uvlinesize, pq); + else + v->vc1dsp.vc1_v_loop_filter16(dst, s->linesize, pq); + } +} + +void ff_vc1_i_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + int mb_pos = s->mb_x + s->mb_y * s->mb_stride; + uint8_t *dest, fieldtx; + uint32_t flags = 0; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on top and internal + * horizontal borders of the last overlap filtered MB. Then, we wait for + * the loop filter iteration on the next row to do V loop filter on the + * bottom edge of this MB, before moving over and running the H loop + * filter on the left and internal vertical borders. Therefore, the loop + * filter trails by one row and one column relative to the overlap filter + * and two rows and two colums relative to the decoding loop. */ + if (!s->first_slice_line) { + dest = s->dest[0] - 16 * s->linesize - 16; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + if (s->mb_x) { + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, flags, fieldtx, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, flags, fieldtx, i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + dest = s->dest[0] - 16; + flags = s->first_slice_line ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + if (s->mb_x) { + fieldtx = v->fieldtx_plane[mb_pos - 1]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, flags, fieldtx, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + fieldtx = v->fieldtx_plane[mb_pos]; + for (i = 0; i < block_count; i++) + vc1_i_v_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, flags, fieldtx, i); + } + } + + if (s->mb_y >= s->start_mb_y + 2) { + dest = s->dest[0] - 32 * s->linesize - 16; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, flags, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, flags, i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, flags, i); + } + if (s->mb_x == s->mb_width - 1) { + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + dest += 16; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, flags, i); + } + } + dest = s->dest[0] - 16; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, flags, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_i_h_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, flags, i); + } + } +} + +static av_always_inline void vc1_p_h_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + uint8_t *is_intra, int16_t (*mv)[2], uint8_t *mv_f, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint32_t left_cbp = cbp[0] >> (block_num * 4), right_cbp; + uint8_t left_is_intra, right_is_intra; + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (!(flags & RIGHT_EDGE) || !(block_num & 5)) { + left_is_intra = is_intra[0] & (1 << block_num); + + if (block_num > 3) { + right_is_intra = is_intra[1] & (1 << block_num); + right_cbp = cbp[1] >> (block_num * 4); + } else if (block_num & 1) { + right_is_intra = is_intra[1] & (1 << block_num - 1); + right_cbp = cbp[1] >> ((block_num - 1) * 4); + } else { + right_is_intra = is_intra[0] & (1 << block_num + 1); + right_cbp = cbp[0] >> ((block_num + 1) * 4); + } + + if (left_is_intra || right_is_intra || + mv[0][0] != mv[1][0] || mv[0][1] != mv[1][1] || + (v->fcm == ILACE_FIELD && mv_f[0] != mv_f[1])) + v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq); + else { + idx = (left_cbp | (right_cbp >> 1)) & 5; + if (idx & 1) + v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 8, linesize, pq); + if (idx & 4) + v->vc1dsp.vc1_h_loop_filter4(dst + 8, linesize, pq); + } + } + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_4X8) { + if (left_cbp & 3) + v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (left_cbp & 12) + v->vc1dsp.vc1_h_loop_filter4(dst + 4, linesize, pq); + } +} + +static av_always_inline void vc1_p_v_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + uint8_t *is_intra, int16_t (*mv)[2], uint8_t *mv_f, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint32_t top_cbp = cbp[0] >> (block_num * 4), bottom_cbp; + uint8_t top_is_intra, bottom_is_intra; + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if(!(flags & BOTTOM_EDGE) || block_num < 2) { + top_is_intra = is_intra[0] & (1 << block_num); + + if (block_num > 3) { + bottom_is_intra = is_intra[s->mb_stride] & (1 << block_num); + bottom_cbp = cbp[s->mb_stride] >> (block_num * 4); + } else if (block_num < 2) { + bottom_is_intra = is_intra[0] & (1 << block_num + 2); + bottom_cbp = cbp[0] >> ((block_num + 2) * 4); + } else { + bottom_is_intra = is_intra[s->mb_stride] & (1 << block_num - 2); + bottom_cbp = cbp[s->mb_stride] >> ((block_num - 2) * 4); + } + + if (top_is_intra || bottom_is_intra || + mv[0][0] != mv[block_num > 3 ? s->mb_stride : s->b8_stride][0] || + mv[0][1] != mv[block_num > 3 ? s->mb_stride : s->b8_stride][1] || + (v->fcm == ILACE_FIELD && mv_f[0] != mv_f[block_num > 3 ? s->mb_stride : s->b8_stride])) + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, linesize, pq); + else { + idx = (top_cbp | (bottom_cbp >> 2)) & 3; + if (idx & 1) + v->vc1dsp.vc1_v_loop_filter4(dst + 8 * linesize + 4, linesize, pq); + if (idx & 2) + v->vc1dsp.vc1_v_loop_filter4(dst + 8 * linesize, linesize, pq); + } + } + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_8X4) { + if (top_cbp & 5) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (top_cbp & 10) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize, linesize, pq); + } +} + +void ff_vc1_p_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + uint8_t *dest; + uint32_t *cbp; + uint8_t *is_intra; + int16_t (*uvmv)[2]; + int *ttblk; + uint32_t flags; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on all applicable + * horizontal borders of the MB above the last overlap filtered MB. Then, + * we wait for the next loop filter iteration to do H loop filter on all + * applicable vertical borders of this MB. Therefore, the loop filter + * trails by one row and one column relative to the overlap filter and two + * rows and two colums relative to the decoding loop. */ + if (s->mb_y >= s->start_mb_y + 2) { + if (s->mb_x) { + dest = s->dest[0] - 32 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1]; + flags = s->mb_y == s->start_mb_y + 2 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + dest = s->dest[0] - 32 * s->linesize; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 2 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_x) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0] - 16; + cbp = &v->cbp[s->mb_x - 1]; + is_intra = &v->is_intra[s->mb_x - 1]; + uvmv = &v->luma_mv[s->mb_x - 1]; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize; + cbp = &v->cbp[s->mb_x - s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0]; + cbp = &v->cbp[s->mb_x]; + is_intra = &v->is_intra[s->mb_x]; + uvmv = &v->luma_mv[s->mb_x]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_v_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off] : + &v->mv_f[0][s->block_index[i] + v->blocks_off], + ttblk, + flags, + i); + } + } + + if (s->mb_y >= s->start_mb_y + 2) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 32 * s->linesize - 32; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 2]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 2]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 2]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 16 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 2 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 4 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 32 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0] - 32 * s->linesize; + cbp = &v->cbp[s->mb_x - 2 * s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - 2 * s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - 2 * s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 * s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 16 * s->linesize - 32; + cbp = &v->cbp[s->mb_x - s->mb_stride - 2]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride - 2]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 2]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 16 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 2 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 4 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - s->mb_stride - 1]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride - 1]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0] - 16 * s->linesize; + cbp = &v->cbp[s->mb_x - s->mb_stride]; + is_intra = &v->is_intra[s->mb_x - s->mb_stride]; + uvmv = &v->luma_mv[s->mb_x - s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - s->mb_stride + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 * s->b8_stride + v->blocks_off], + ttblk, + flags, + i); + } + } + if (s->mb_x >= 2) { + dest = s->dest[0] - 32; + cbp = &v->cbp[s->mb_x - 2]; + is_intra = &v->is_intra[s->mb_x - 2]; + uvmv = &v->luma_mv[s->mb_x - 2]; + ttblk = &v->ttblk[s->mb_x - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 4 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 2 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 4 + v->blocks_off], + ttblk, + flags, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16; + cbp = &v->cbp[s->mb_x - 1]; + is_intra = &v->is_intra[s->mb_x - 1]; + uvmv = &v->luma_mv[s->mb_x - 1]; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] - 2 + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] - 1 + v->mb_off] : + &v->mv_f[0][s->block_index[i] - 2 + v->blocks_off], + ttblk, + flags, + i); + } + dest = s->dest[0]; + cbp = &v->cbp[s->mb_x]; + is_intra = &v->is_intra[s->mb_x]; + uvmv = &v->luma_mv[s->mb_x]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_p_h_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + cbp, + is_intra, + i > 3 ? uvmv : + &s->current_picture.motion_val[0][s->block_index[i] + v->blocks_off], + i > 3 ? &v->mv_f[0][s->block_index[i] + v->mb_off] : + &v->mv_f[0][s->block_index[i] + v->blocks_off], + ttblk, + flags, + i); + } + } +} + +static av_always_inline void vc1_p_h_intfr_loop_filter(VC1Context *v, uint8_t *dest, int *ttblk, + uint32_t flags, uint8_t fieldtx, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + int tt; + int linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (block_num < 4) { + if (fieldtx) { + if (block_num < 2) { + if (tt == TT_4X4 || tt == TT_4X8) + v->vc1dsp.vc1_h_loop_filter8(dst + 4, 2 * linesize, pq); + if (!(flags & RIGHT_EDGE) || block_num == 0) + v->vc1dsp.vc1_h_loop_filter8(dst + 8, 2 * linesize, pq); + } else { + if (tt == TT_4X4 || tt == TT_4X8) + v->vc1dsp.vc1_h_loop_filter8(dst - 7 * linesize + 4, 2 * linesize, pq); + if (!(flags & RIGHT_EDGE) || block_num == 2) + v->vc1dsp.vc1_h_loop_filter8(dst - 7 * linesize + 8, 2 * linesize, pq); + } + } else { + if(tt == TT_4X4 || tt == TT_4X8) { + v->vc1dsp.vc1_h_loop_filter4(dst + 4, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 4, 2 * linesize, pq); + } + if (!(flags & RIGHT_EDGE) || !(block_num & 5)) { + v->vc1dsp.vc1_h_loop_filter4(dst + 8, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 8, 2 * linesize, pq); + } + } + } else { + if (tt == TT_4X4 || tt == TT_4X8) { + v->vc1dsp.vc1_h_loop_filter4(dst + 4, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 4, 2 * linesize, pq); + } + if (!(flags & RIGHT_EDGE)) { + v->vc1dsp.vc1_h_loop_filter4(dst + 8, 2 * linesize, pq); + v->vc1dsp.vc1_h_loop_filter4(dst + linesize + 8, 2 * linesize, pq); + } + } +} + +static av_always_inline void vc1_p_v_intfr_loop_filter(VC1Context *v, uint8_t *dest, int *ttblk, + uint32_t flags, uint8_t fieldtx, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + int tt; + int linesize = block_num > 3 ? s->uvlinesize : s->linesize; + uint8_t *dst; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (block_num < 4) { + if (fieldtx) { + if (block_num < 2) { + if (tt == TT_4X4 || tt == TT_8X4) + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + if (!(flags & BOTTOM_EDGE)) + v->vc1dsp.vc1_v_loop_filter8(dst + 16 * linesize, 2 * linesize, pq); + } else { + if (tt == TT_4X4 || tt == TT_8X4) + v->vc1dsp.vc1_v_loop_filter8(dst + linesize, 2 * linesize, pq); + if (!(flags & BOTTOM_EDGE)) + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } + } else { + if (block_num < 2) { + if (!(flags & TOP_EDGE) && (tt == TT_4X4 || tt == TT_8X4)) { + v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq); + } + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } else if (!(flags & BOTTOM_EDGE)) { + if (tt == TT_4X4 || tt == TT_8X4) { + v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq); + } + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } + } + } else { + if (!(flags & BOTTOM_EDGE)) { + if (!(flags & TOP_EDGE) && (tt == TT_4X4 || tt == TT_8X4)) { + v->vc1dsp.vc1_v_loop_filter8(dst + 4 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 5 * linesize, 2 * linesize, pq); + } + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, 2 * linesize, pq); + v->vc1dsp.vc1_v_loop_filter8(dst + 9 * linesize, 2 * linesize, pq); + } + } +} + +void ff_vc1_p_intfr_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + int mb_pos = s->mb_x + s->mb_y * s->mb_stride; + uint8_t *dest; + int *ttblk; + uint32_t flags; + uint8_t fieldtx; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on all applicable + * horizontal borders of the MB above the last overlap filtered MB. Then, + * we wait for the loop filter iteration on the next row and next column to + * do H loop filter on all applicable vertical borders of this MB. + * Therefore, the loop filter trails by two rows and one column relative to + * the overlap filter and two rows and two colums relative to the decoding + * loop. */ + if (s->mb_x) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + dest = s->dest[0] - 16 * s->linesize; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_x) { + dest = s->dest[0] - 16; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + fieldtx = v->fieldtx_plane[mb_pos - 1]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + dest = s->dest[0]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_y == s->start_mb_y ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + fieldtx = v->fieldtx_plane[mb_pos]; + for (i = 0; i < block_count; i++) + vc1_p_v_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + ttblk, + flags, + fieldtx, + i); + } + } + + if (s->mb_y >= s->start_mb_y + 2) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 32 * s->linesize - 32; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride - 2]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 16 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 32 * s->linesize - 16; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + dest = s->dest[0] - 32 * s->linesize; + ttblk = &v->ttblk[s->mb_x - 2 * s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + fieldtx = v->fieldtx_plane[mb_pos - 2 * s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 * s->uvlinesize : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + if (s->mb_y >= s->start_mb_y + 1) { + if (s->mb_x >= 2) { + dest = s->dest[0] - 16 * s->linesize - 32; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 2]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 16 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16 * s->linesize - 16; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride - 1]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + dest = s->dest[0] - 16 * s->linesize; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + fieldtx = v->fieldtx_plane[mb_pos - s->mb_stride]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, + ttblk, + flags, + fieldtx, + i); + } + } + if (s->mb_x >= 2) { + dest = s->dest[0] - 32; + ttblk = &v->ttblk[s->mb_x - 2]; + flags = s->mb_x == 2 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 2]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 16 : dest, + ttblk, + flags, + fieldtx, + i); + } + if (s->mb_x == s->mb_width - 1) { + if (s->mb_x >= 1) { + dest = s->dest[0] - 16; + ttblk = &v->ttblk[s->mb_x - 1]; + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + fieldtx = v->fieldtx_plane[mb_pos - 1]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] - 8 : dest, + ttblk, + flags, + fieldtx, + i); + } + dest = s->dest[0]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->mb_x ? RIGHT_EDGE : LEFT_EDGE | RIGHT_EDGE; + fieldtx = v->fieldtx_plane[mb_pos]; + for (i = 0; i < block_count; i++) + vc1_p_h_intfr_loop_filter(v, + i > 3 ? s->dest[i - 3] : dest, + ttblk, + flags, + fieldtx, + i); + } + } +} + +static av_always_inline void vc1_b_h_intfi_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + uint32_t block_cbp = cbp[0] >> (block_num * 4); + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if (!(flags & RIGHT_EDGE) || !(block_num & 5)) { + if (block_num > 3) + v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq); + else + v->vc1dsp.vc1_h_loop_filter8(dst + 8, linesize, pq); + } + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_4X8) { + idx = (block_cbp | (block_cbp >> 1)) & 5; + if (idx & 1) + v->vc1dsp.vc1_h_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (idx & 4) + v->vc1dsp.vc1_h_loop_filter4(dst + 4, linesize, pq); + } +} + +static av_always_inline void vc1_b_v_intfi_loop_filter(VC1Context *v, uint8_t *dest, uint32_t *cbp, + int *ttblk, uint32_t flags, int block_num) +{ + MpegEncContext *s = &v->s; + int pq = v->pq; + uint8_t *dst; + uint32_t block_cbp = cbp[0] >> (block_num * 4); + int tt; + int idx, linesize = block_num > 3 ? s->uvlinesize : s->linesize; + + if (block_num > 3) + dst = dest; + else + dst = dest + (block_num & 2) * 4 * s->linesize + (block_num & 1) * 8; + + if(!(flags & BOTTOM_EDGE) || block_num < 2) + v->vc1dsp.vc1_v_loop_filter8(dst + 8 * linesize, linesize, pq); + + tt = ttblk[0] >> (block_num * 4) & 0xf; + if (tt == TT_4X4 || tt == TT_8X4) { + idx = (block_cbp | (block_cbp >> 2)) & 3; + if (idx & 1) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize + 4, linesize, pq); + if (idx & 2) + v->vc1dsp.vc1_v_loop_filter4(dst + 4 * linesize, linesize, pq); + } +} + +void ff_vc1_b_intfi_loop_filter(VC1Context *v) +{ + MpegEncContext *s = &v->s; + int block_count = CONFIG_GRAY && (s->avctx->flags & AV_CODEC_FLAG_GRAY) ? 4 : 6; + uint8_t *dest; + uint32_t *cbp; + int *ttblk; + uint32_t flags = 0; + int i; + + /* Within a MB, the vertical loop filter always runs before the horizontal. + * To accomplish that, we run the V loop filter on all applicable + * horizontal borders of the MB above the currently decoded MB. Then, + * we wait for the next loop filter iteration to do H loop filter on all + * applicable vertical borders of this MB. Therefore, the loop filter + * trails by one row and one column relative to the decoding loop. */ + if (!s->first_slice_line) { + dest = s->dest[0] - 16 * s->linesize; + cbp = &v->cbp[s->mb_x - s->mb_stride]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride]; + flags = s->mb_y == s->start_mb_y + 1 ? TOP_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_b_v_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, ttblk, flags, i); + } + if (s->mb_y == s->end_mb_y - 1) { + dest = s->dest[0]; + cbp = &v->cbp[s->mb_x]; + ttblk = &v->ttblk[s->mb_x]; + flags = s->first_slice_line ? TOP_EDGE | BOTTOM_EDGE : BOTTOM_EDGE; + for (i = 0; i < block_count; i++) + vc1_b_v_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, ttblk, flags, i); + } + + if (!s->first_slice_line) { + dest = s->dest[0] - 16 * s->linesize - 16; + cbp = &v->cbp[s->mb_x - s->mb_stride - 1]; + ttblk = &v->ttblk[s->mb_x - s->mb_stride - 1]; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize - 8 : dest, cbp, ttblk, flags, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + cbp++; + ttblk++; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 * s->uvlinesize : dest, cbp, ttblk, flags, i); + } + } + if (s->mb_y == s->end_mb_y - 1) { + dest = s->dest[0] - 16; + cbp = &v->cbp[s->mb_x - 1]; + ttblk = &v->ttblk[s->mb_x - 1]; + if (s->mb_x) { + flags = s->mb_x == 1 ? LEFT_EDGE : 0; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] - 8 : dest, cbp, ttblk, flags, i); + } + if (s->mb_x == s->mb_width - 1) { + dest += 16; + cbp++; + ttblk++; + flags = s->mb_x == 0 ? LEFT_EDGE | RIGHT_EDGE : RIGHT_EDGE; + for (i = 0; i < block_count; i++) + vc1_b_h_intfi_loop_filter(v, i > 3 ? s->dest[i - 3] : dest, cbp, ttblk, flags, i); + } + } +}