diff --git a/packages/audio/dcadec/package.mk b/packages/audio/dcadec/package.mk
deleted file mode 100644
index 59a5a6d2a2..0000000000
--- a/packages/audio/dcadec/package.mk
+++ /dev/null
@@ -1,48 +0,0 @@
-################################################################################
-# This file is part of OpenELEC - http://www.openelec.tv
-# Copyright (C) 2009-2016 Stephan Raue (stephan@openelec.tv)
-#
-# OpenELEC is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 2 of the License, or
-# (at your option) any later version.
-#
-# OpenELEC is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with OpenELEC. If not, see .
-################################################################################
-
-PKG_NAME="dcadec"
-PKG_VERSION="0e07438"
-PKG_REV="1"
-PKG_ARCH="any"
-PKG_LICENSE="GPL"
-PKG_SITE="https://github.com/foo86/dcadec"
-PKG_URL="https://github.com/foo86/dcadec/archive/$PKG_VERSION.tar.gz"
-PKG_DEPENDS_TARGET="toolchain"
-PKG_PRIORITY="optional"
-PKG_SECTION="audio"
-PKG_SHORTDESC="DTS Coherent Acoustics decoder with support for HD extensions"
-PKG_LONGDESC="DTS Coherent Acoustics decoder with support for HD extensions"
-
-PKG_IS_ADDON="no"
-PKG_AUTORECONF="no"
-
-# todo: we need to build as shared library, otherwise sond dont work
-# in kodi with enabled dcadec support and we have 100% CPU usage
-# (to test disable passtrough and use a DTS-HD sample)
-PKG_MAKE_OPTS_TARGET="PREFIX=/usr BINDIR=/usr/bin LIBDIR=/usr/lib INCLUDEDIR=/usr/include PKG_CONFIG_PATH=/usr/lib/pkgconfig CONFIG_SHARED=1"
-PKG_MAKEINSTALL_OPTS_TARGET="$PKG_MAKE_OPTS_TARGET"
-
-pre_configure_target() {
- export CFLAGS="$CFLAGS -fPIC -DPIC"
- export LDFLAGS="$LDFLAGS -fPIC -DPIC"
-}
-
-post_makeinstall_target() {
- rm -rf $INSTALL/usr/bin
-}
diff --git a/packages/multimedia/ffmpeg/package.mk b/packages/multimedia/ffmpeg/package.mk
index 98784e4aa2..6cb04e52e0 100644
--- a/packages/multimedia/ffmpeg/package.mk
+++ b/packages/multimedia/ffmpeg/package.mk
@@ -17,13 +17,14 @@
################################################################################
PKG_NAME="ffmpeg"
-PKG_VERSION="2.8.6"
+PKG_VERSION="3.0-xbmc"
PKG_REV="1"
PKG_ARCH="any"
PKG_LICENSE="LGPLv2.1+"
PKG_SITE="https://ffmpeg.org"
-PKG_URL="https://ffmpeg.org/releases/${PKG_NAME}-${PKG_VERSION}.tar.gz"
-PKG_DEPENDS_TARGET="toolchain yasm:host zlib bzip2 libvorbis libressl dcadec speex"
+PKG_URL="https://github.com/xbmc/FFmpeg/archive/release/${PKG_VERSION}.tar.gz"
+PKG_SOURCE_DIR="FFmpeg-release-${PKG_VERSION}"
+PKG_DEPENDS_TARGET="toolchain yasm:host zlib bzip2 libvorbis libressl speex"
PKG_PRIORITY="optional"
PKG_SECTION="multimedia"
PKG_SHORTDESC="FFmpeg is a complete, cross-platform solution to record, convert and stream audio and video."
@@ -194,7 +195,6 @@ configure_target() {
--disable-libopencore-amrwb \
--disable-libopencv \
--disable-libdc1394 \
- --enable-libdcadec \
--disable-libfaac \
--disable-libfreetype \
--disable-libgsm \
@@ -205,7 +205,6 @@ configure_target() {
--disable-libschroedinger \
--enable-libspeex \
--disable-libtheora \
- --disable-libvo-aacenc \
--disable-libvo-amrwbenc \
--enable-libvorbis --enable-muxer=ogg --enable-encoder=libvorbis \
--disable-libvpx \
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-010-kodi.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-010-kodi.patch
deleted file mode 100644
index 27b2c1b973..0000000000
--- a/packages/multimedia/ffmpeg/patches/ffmpeg-010-kodi.patch
+++ /dev/null
@@ -1,585 +0,0 @@
-From 007ee4796d1621ef6070fdef9aa10ff227ee20b4 Mon Sep 17 00:00:00 2001
-From: Joakim Plate
-Date: Sun, 11 Sep 2011 19:04:51 +0200
-Subject: [PATCH 01/13] Support raw dvdsub palette as stored on normal dvd's
-
-This is how the palette is stored on dvd's. Currently
-only xbmc passes the palette information to libavcodec
-this way.
----
- libavcodec/dvdsubdec.c | 24 ++++++++++++++++++++++++
- 1 file changed, 24 insertions(+)
-
-diff --git a/libavcodec/dvdsubdec.c b/libavcodec/dvdsubdec.c
-index f009824..bbee694 100644
---- a/libavcodec/dvdsubdec.c
-+++ b/libavcodec/dvdsubdec.c
-@@ -64,6 +64,24 @@ static void yuv_a_to_rgba(const uint8_t *ycbcr, const uint8_t *alpha, uint32_t *
- }
- }
-
-+static void ayvu_to_argb(const uint8_t *ayvu, uint32_t *argb, int num_values)
-+{
-+ uint8_t *cm = ff_crop_tab + MAX_NEG_CROP;
-+ uint8_t r, g, b;
-+ int i, y, cb, cr, a;
-+ int r_add, g_add, b_add;
-+
-+ for (i = num_values; i > 0; i--) {
-+ a = *ayvu++;
-+ y = *ayvu++;
-+ cr = *ayvu++;
-+ cb = *ayvu++;
-+ YUV_TO_RGB1_CCIR(cb, cr);
-+ YUV_TO_RGB2_CCIR(r, g, b, y);
-+ *argb++ = (a << 24) | (r << 16) | (g << 8) | b;
-+ }
-+}
-+
- static int decode_run_2bit(GetBitContext *gb, int *color)
- {
- unsigned int v, t;
-@@ -708,6 +726,12 @@ static av_cold int dvdsub_init(AVCodecContext *avctx)
- parse_ifo_palette(ctx, ctx->ifo_str);
- if (ctx->palette_str)
- parse_palette(ctx, ctx->palette_str);
-+
-+ if (!ctx->has_palette && avctx->extradata_size == 64) {
-+ ayvu_to_argb((uint8_t*)avctx->extradata, ctx->palette, 16);
-+ ctx->has_palette = 1;
-+ }
-+
- if (ctx->has_palette) {
- int i;
- av_log(avctx, AV_LOG_DEBUG, "palette:");
-
-From 3b001c5375fdcb0fca89c813bf808da35f904323 Mon Sep 17 00:00:00 2001
-From: Cory Fields
-Date: Mon, 28 Jun 2010 01:55:31 -0400
-Subject: [PATCH 02/13] if av_read_packet returns AVERROR_IO, we are done.
- ffmpeg's codecs might or might not handle returning any completed demuxed
- packets correctly
-
----
- libavformat/utils.c | 2 ++
- 1 file changed, 2 insertions(+)
-
-diff --git a/libavformat/utils.c b/libavformat/utils.c
-index 30567fa..8a947d6 100644
---- a/libavformat/utils.c
-+++ b/libavformat/utils.c
-@@ -1329,6 +1329,8 @@ static int read_frame_internal(AVFormatContext *s, AVPacket *pkt)
- if (ret < 0) {
- if (ret == AVERROR(EAGAIN))
- return ret;
-+ if (ret == AVERROR(EIO))
-+ return ret;
- /* flush the parsers */
- for (i = 0; i < s->nb_streams; i++) {
- st = s->streams[i];
-
-From 75902cb6825c581853636147020f1be99aba198c Mon Sep 17 00:00:00 2001
-From: Cory Fields
-Date: Mon, 28 Jun 2010 02:10:50 -0400
-Subject: [PATCH 03/13] added: Ticket #7187, TV Teletext support for DVB EBU
- Teletext streams
-
----
- libavcodec/avcodec.h | 4 ++++
- libavformat/mpegts.c | 2 ++
- 2 files changed, 6 insertions(+)
-
-diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
-index 9d38b59..bc1b1b9 100644
---- a/libavcodec/avcodec.h
-+++ b/libavcodec/avcodec.h
-@@ -532,6 +532,10 @@ enum AVCodecID {
- AV_CODEC_ID_ASS = MKBETAG('A','S','S',' '), ///< ASS as defined in Matroska
- AV_CODEC_ID_HDMV_TEXT_SUBTITLE = MKBETAG('B','D','T','X'),
-
-+ /* data codecs */
-+ AV_CODEC_ID_VBI_DATA= 0x17500,
-+ AV_CODEC_ID_VBI_TELETEXT,
-+
- /* other specific kind of codecs (generally used for attachments) */
- AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs.
- AV_CODEC_ID_TTF = 0x18000,
-diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
-index 65824dd..338861e 100644
---- a/libavformat/mpegts.c
-+++ b/libavformat/mpegts.c
-@@ -756,6 +756,8 @@ static const StreamType DESC_types[] = {
- { 0x7b, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS },
- { 0x56, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_TELETEXT },
- { 0x59, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_SUBTITLE }, /* subtitling descriptor */
-+ { 0x45, AVMEDIA_TYPE_DATA, AV_CODEC_ID_VBI_DATA }, /* VBI Data descriptor */
-+ { 0x46, AVMEDIA_TYPE_DATA, AV_CODEC_ID_VBI_TELETEXT }, /* VBI Teletext descriptor */
- { 0 },
- };
-
-
-From fabf7216626da8caecf9cb34b188739e530cc8d4 Mon Sep 17 00:00:00 2001
-From: Joakim Plate
-Date: Sun, 18 Sep 2011 19:16:34 +0200
-Subject: [PATCH 04/13] Don't accept mpegts PMT that isn't current
-
----
- libavformat/mpegts.c | 4 ++++
- 1 file changed, 4 insertions(+)
-
-diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
-index 338861e..d4168c8 100644
---- a/libavformat/mpegts.c
-+++ b/libavformat/mpegts.c
-@@ -585,6 +585,7 @@ typedef struct SectionHeader {
- uint8_t tid;
- uint16_t id;
- uint8_t version;
-+ uint8_t current;
- uint8_t sec_num;
- uint8_t last_sec_num;
- } SectionHeader;
-@@ -667,6 +668,7 @@ static int parse_section_header(SectionHeader *h,
- val = get8(pp, p_end);
- if (val < 0)
- return val;
-+ h->current = val & 0x1;
- h->version = (val >> 1) & 0x1f;
- val = get8(pp, p_end);
- if (val < 0)
-@@ -2020,6 +2022,8 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
- return;
- if (ts->skip_changes)
- return;
-+ if (!h->current)
-+ return;
-
- if (skip_identical(h, tssf))
- return;
-
-From 4f1d8668a50ebf7cddc03d191c72c36fca2146dc Mon Sep 17 00:00:00 2001
-From: Joakim Plate
-Date: Sun, 18 Sep 2011 19:17:23 +0200
-Subject: [PATCH 05/13] Don't reparse PMT unless it's version has changed
-
----
- libavformat/mpegts.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
-index d4168c8..9c6f6dc 100644
---- a/libavformat/mpegts.c
-+++ b/libavformat/mpegts.c
-@@ -91,6 +91,7 @@ struct MpegTSFilter {
- int es_id;
- int last_cc; /* last cc code (-1 if first packet) */
- int64_t last_pcr;
-+ int last_version; /* last version of data on this pid */
- enum MpegTSFilterType type;
- union {
- MpegTSPESFilter pes_filter;
-@@ -459,6 +460,7 @@ static MpegTSFilter *mpegts_open_filter(MpegTSContext *ts, unsigned int pid,
- filter->es_id = -1;
- filter->last_cc = -1;
- filter->last_pcr= -1;
-+ filter->last_version = -1;
-
- return filter;
- }
-@@ -2024,6 +2026,10 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
- return;
- if (!h->current)
- return;
-+ if (h->version == filter->last_version)
-+ return;
-+ filter->last_version = h->version;
-+ av_dlog(ts->stream, "version=%d\n", filter->last_version);
-
- if (skip_identical(h, tssf))
- return;
-
-From 72cf6cb34af9de7e81bffc6a53f7d1f450e5b624 Mon Sep 17 00:00:00 2001
-From: Cory Fields
-Date: Fri, 9 Jul 2010 16:43:31 -0400
-Subject: [PATCH 06/13] Read PID timestamps as well as PCR timestamps to find
- location in mpegts stream
-
----
- libavformat/mpegts.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
- 1 file changed, 46 insertions(+), 2 deletions(-)
-
-diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
-index 9c6f6dc..a4db558 100644
---- a/libavformat/mpegts.c
-+++ b/libavformat/mpegts.c
-@@ -2519,6 +2519,44 @@ static void seek_back(AVFormatContext *s, AVIOContext *pb, int64_t pos) {
- av_log(s, pb->seekable ? AV_LOG_ERROR : AV_LOG_INFO, "Unable to seek back to the start\n");
- }
-
-+static int parse_timestamp(int64_t *ts, const uint8_t *buf)
-+{
-+ int afc, flags;
-+ const uint8_t *p;
-+
-+ if(!(buf[1] & 0x40)) /* must be a start packet */
-+ return -1;
-+
-+ afc = (buf[3] >> 4) & 3;
-+ p = buf + 4;
-+ if (afc == 0 || afc == 2) /* invalid or only adaption field */
-+ return -1;
-+ if (afc == 3)
-+ p += p[0] + 1;
-+ if (p >= buf + TS_PACKET_SIZE)
-+ return -1;
-+
-+ if (p[0] != 0x00 || p[1] != 0x00 || p[2] != 0x01) /* packet_start_code_prefix */
-+ return -1;
-+
-+ flags = p[3] | 0x100; /* stream type */
-+ if (!((flags >= 0x1c0 && flags <= 0x1df) ||
-+ (flags >= 0x1e0 && flags <= 0x1ef) ||
-+ (flags == 0x1bd) || (flags == 0x1fd)))
-+ return -1;
-+
-+ flags = p[7];
-+ if ((flags & 0xc0) == 0x80) {
-+ *ts = ff_parse_pes_pts(p+9);
-+ return 0;
-+ } else if ((flags & 0xc0) == 0xc0) {
-+ *ts = ff_parse_pes_pts(p+9+5);
-+ return 0;
-+ }
-+ return -1;
-+}
-+
-+
- static int mpegts_read_header(AVFormatContext *s)
- {
- MpegTSContext *ts = s->priv_data;
-@@ -2724,6 +2762,7 @@ static av_unused int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
- uint8_t buf[TS_PACKET_SIZE];
- int pcr_l, pcr_pid =
- ((PESContext *)s->streams[stream_index]->priv_data)->pcr_pid;
-+ int pid = ((PESContext*)s->streams[stream_index]->priv_data)->pid;
- int pos47 = ts->pos47_full % ts->raw_packet_size;
- pos =
- ((*ppos + ts->raw_packet_size - 1 - pos47) / ts->raw_packet_size) *
-@@ -2745,6 +2784,11 @@ static av_unused int64_t mpegts_get_pcr(AVFormatContext *s, int stream_index,
- *ppos = pos;
- return timestamp;
- }
-+ if ((pid < 0 || (AV_RB16(buf + 1) & 0x1fff) == pid) &&
-+ parse_timestamp(×tamp, buf) == 0) {
-+ *ppos = pos;
-+ return timestamp;
-+ }
- pos += ts->raw_packet_size;
- }
-
-@@ -2844,7 +2888,7 @@ AVInputFormat ff_mpegts_demuxer = {
- .read_header = mpegts_read_header,
- .read_packet = mpegts_read_packet,
- .read_close = mpegts_read_close,
-- .read_timestamp = mpegts_get_dts,
-+ .read_timestamp = mpegts_get_pcr,
- .flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
- .priv_class = &mpegts_class,
- };
-@@ -2856,7 +2900,7 @@ AVInputFormat ff_mpegtsraw_demuxer = {
- .read_header = mpegts_read_header,
- .read_packet = mpegts_raw_read_packet,
- .read_close = mpegts_read_close,
-- .read_timestamp = mpegts_get_dts,
-+ .read_timestamp = mpegts_get_pcr,
- .flags = AVFMT_SHOW_IDS | AVFMT_TS_DISCONT,
- .priv_class = &mpegtsraw_class,
- };
-
-From ee8a688e4e6f59785180c1e92981ff867f6f5c23 Mon Sep 17 00:00:00 2001
-From: Joakim Plate
-Date: Sat, 22 Oct 2011 19:01:38 +0200
-Subject: [PATCH 07/13] Get stream durations using read_timestamp
-
----
- libavformat/utils.c | 39 +++++++++++++++++++++++++++++++++++++++
- 1 file changed, 39 insertions(+)
-
-diff --git a/libavformat/utils.c b/libavformat/utils.c
-index 8a947d6..88786f1 100644
---- a/libavformat/utils.c
-+++ b/libavformat/utils.c
-@@ -2455,6 +2455,41 @@ static void estimate_timings_from_bit_rate(AVFormatContext *ic)
- #define DURATION_MAX_READ_SIZE 250000LL
- #define DURATION_MAX_RETRY 6
-
-+static void av_estimate_timings_from_pts2(AVFormatContext *ic, int64_t old_offset)
-+{
-+ AVStream *st;
-+ int i, step= 1024;
-+ int64_t ts, pos;
-+
-+ for(i=0;inb_streams;i++) {
-+ st = ic->streams[i];
-+
-+ pos = 0;
-+ ts = ic->iformat->read_timestamp(ic, i, &pos, DURATION_MAX_READ_SIZE);
-+ if (ts == AV_NOPTS_VALUE)
-+ continue;
-+ if (st->start_time > ts || st->start_time == AV_NOPTS_VALUE)
-+ st->start_time = ts;
-+
-+ pos = avio_size(ic->pb) - 1;
-+ do {
-+ pos -= step;
-+ ts = ic->iformat->read_timestamp(ic, i, &pos, pos + step);
-+ step += step;
-+ } while (ts == AV_NOPTS_VALUE && pos >= step && step < DURATION_MAX_READ_SIZE);
-+
-+ if (ts == AV_NOPTS_VALUE)
-+ continue;
-+
-+ if (st->duration < ts - st->start_time || st->duration == AV_NOPTS_VALUE)
-+ st->duration = ts - st->start_time;
-+ }
-+
-+ fill_all_stream_timings(ic);
-+
-+ avio_seek(ic->pb, old_offset, SEEK_SET);
-+}
-+
- /* only usable for MPEG-PS streams */
- static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
- {
-@@ -2605,6 +2640,10 @@ static void estimate_timings(AVFormatContext *ic, int64_t old_offset)
- * the components */
- fill_all_stream_timings(ic);
- ic->duration_estimation_method = AVFMT_DURATION_FROM_STREAM;
-+ } else if (ic->iformat->read_timestamp &&
-+ file_size && ic->pb->seekable) {
-+ /* get accurate estimate from the PTSes */
-+ av_estimate_timings_from_pts2(ic, old_offset);
- } else {
- /* less precise: use bitrate info */
- estimate_timings_from_bit_rate(ic);
-
-From a45171f7370c263344805d19181e08a12a65dcdd Mon Sep 17 00:00:00 2001
-From: Joakim Plate
-Date: Wed, 8 Dec 2010 14:03:43 +0000
-Subject: [PATCH 08/13] changed: allow 4 second skew between streams in mov
- before attempting to seek
-
----
- libavformat/mov.c | 4 ++--
- 1 file changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/libavformat/mov.c b/libavformat/mov.c
-index 4ce4e2d..2c364ac 100644
---- a/libavformat/mov.c
-+++ b/libavformat/mov.c
-@@ -4624,8 +4624,8 @@ static AVIndexEntry *mov_find_next_sample(AVFormatContext *s, AVStream **st)
- if (!sample || (!s->pb->seekable && current_sample->pos < sample->pos) ||
- (s->pb->seekable &&
- ((msc->pb != s->pb && dts < best_dts) || (msc->pb == s->pb &&
-- ((FFABS(best_dts - dts) <= AV_TIME_BASE && current_sample->pos < sample->pos) ||
-- (FFABS(best_dts - dts) > AV_TIME_BASE && dts < best_dts)))))) {
-+ ((FFABS(best_dts - dts) <= 4*AV_TIME_BASE && current_sample->pos < sample->pos) ||
-+ (FFABS(best_dts - dts) > 4*AV_TIME_BASE && dts < best_dts)))))) {
- sample = current_sample;
- best_dts = dts;
- *st = avst;
-
-From c3e8fbd02c2eaba2a5d14d2b6c07fe08746f5947 Mon Sep 17 00:00:00 2001
-From: Joakim Plate
-Date: Fri, 26 Nov 2010 20:56:48 +0000
-Subject: [PATCH 09/13] fixed: memleak in mpegts demuxer on some malformed (??)
- mpegts files with too large pes packets
-
-at-visions sample file brokenStream.mpg
----
- libavformat/mpegts.c | 6 ++++++
- 1 file changed, 6 insertions(+)
-
-diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
-index a4db558..492d9c7 100644
---- a/libavformat/mpegts.c
-+++ b/libavformat/mpegts.c
-@@ -868,6 +868,10 @@ static void reset_pes_packet_state(PESContext *pes)
-
- static void new_pes_packet(PESContext *pes, AVPacket *pkt)
- {
-+ if(pkt->data) {
-+ av_log(pes->stream, AV_LOG_ERROR, "ignoring previously allocated packet on stream %d\n", pkt->stream_index);
-+ av_free_packet(pkt);
-+ }
- av_init_packet(pkt);
-
- pkt->buf = pes->buffer;
-@@ -2715,6 +2719,8 @@ static int mpegts_read_packet(AVFormatContext *s, AVPacket *pkt)
-
- pkt->size = -1;
- ts->pkt = pkt;
-+ ts->pkt->data = NULL;
-+
- ret = handle_packets(ts, 0);
- if (ret < 0) {
- av_free_packet(ts->pkt);
-
-From eba5c839b7e24f8e6800d3f923d5334c2c9e6b2d Mon Sep 17 00:00:00 2001
-From: Joakim Plate
-Date: Mon, 28 Jun 2010 21:26:54 +0000
-Subject: [PATCH 10/13] Speed up mpegts av_find_stream_info
-
----
- libavformat/mpegts.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
-index 492d9c7..29d58eb 100644
---- a/libavformat/mpegts.c
-+++ b/libavformat/mpegts.c
-@@ -1030,7 +1030,7 @@ static int mpegts_push_data(MpegTSFilter *filter,
- goto skip;
-
- /* stream not present in PMT */
-- if (!pes->st) {
-+ if (ts->auto_guess && !pes->st) {
- if (ts->skip_changes)
- goto skip;
-
-
-From 2372b27243eb7d0932d9885558708ba115596d0b Mon Sep 17 00:00:00 2001
-From: marc
-Date: Mon, 18 Feb 2013 17:18:18 +0000
-Subject: [PATCH 11/13] dxva-h264 Fix dxva playback of streams that don't start
- with an I-Frame (adjusted to 2.7)
-
----
- libavcodec/dxva2_h264.c | 8 ++++++++
- libavcodec/h264.c | 1 +
- libavcodec/h264.h | 2 ++
- libavcodec/h264_slice.c | 1 +
- 4 files changed, 12 insertions(+)
-
-diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c
-index 99b80ba..eb5ecd1 100644
---- a/libavcodec/dxva2_h264.c
-+++ b/libavcodec/dxva2_h264.c
-@@ -497,6 +497,14 @@ static int dxva2_h264_end_frame(AVCodecContext *avctx)
-
- if (ctx_pic->slice_count <= 0 || ctx_pic->bitstream_size <= 0)
- return -1;
-+
-+ // Wait for an I-frame before start decoding. Workaround for ATI UVD and UVD+ GPUs
-+ if (!h->got_first_iframe) {
-+ if (!(ctx_pic->pp.wBitFields & (1 << 15)))
-+ return -1;
-+ h->got_first_iframe = 1;
-+ }
-+
- ret = ff_dxva2_common_end_frame(avctx, h->cur_pic_ptr->f,
- &ctx_pic->pp, sizeof(ctx_pic->pp),
- &ctx_pic->qm, sizeof(ctx_pic->qm),
-diff --git a/libavcodec/h264.c b/libavcodec/h264.c
-index 907943e..718b746 100644
---- a/libavcodec/h264.c
-+++ b/libavcodec/h264.c
-@@ -1087,6 +1087,7 @@ void ff_h264_flush_change(H264Context *h)
-
- h->next_outputed_poc = INT_MIN;
- h->prev_interlaced_frame = 1;
-+ h->got_first_iframe = 0;
- idr(h);
-
- h->prev_frame_num = -1;
-diff --git a/libavcodec/h264.h b/libavcodec/h264.h
-index 7356288..907ee5e 100644
---- a/libavcodec/h264.h
-+++ b/libavcodec/h264.h
-@@ -813,6 +813,8 @@ typedef struct H264Context {
- * slices) anymore */
- int setup_finished;
-
-+ int got_first_iframe;
-+
- // Timestamp stuff
- int sei_buffering_period_present; ///< Buffering period SEI flag
- int initial_cpb_removal_delay[32]; ///< Initial timestamps for CPBs
-diff --git a/libavcodec/h264_slice.c b/libavcodec/h264_slice.c
-index 8be803b7..939d02b 100644
---- a/libavcodec/h264_slice.c
-+++ b/libavcodec/h264_slice.c
-@@ -1043,6 +1043,7 @@ static int h264_slice_header_init(H264Context *h)
-
- h->first_field = 0;
- h->prev_interlaced_frame = 1;
-+ h->got_first_iframe = 0;
-
- init_scan_tables(h);
- ret = ff_h264_alloc_tables(h);
-
-From 959b88473b6f76fb2245f329ef604d2066b2cb89 Mon Sep 17 00:00:00 2001
-From: wsnipex
-Date: Mon, 16 Feb 2015 09:58:28 +0100
-Subject: [PATCH 12/13] only check for a git rev if the src tree is in a git
- repo
-
-fixes the version string when building from the kodi depends src tree
----
- version.sh | 36 +++++++++++++++++++-----------------
- 1 file changed, 19 insertions(+), 17 deletions(-)
-
-diff --git a/version.sh b/version.sh
-index f9754eb..cc23f80 100755
---- a/version.sh
-+++ b/version.sh
-@@ -2,30 +2,32 @@
-
- # Usage: version.sh
-
-+if [ -d $1/.git ]; then # only check for a git rev, if the src tree is in a git repo
- # check for git short hash
--if ! test "$revision"; then
-+ if ! test "$revision"; then
- if (cd "$1" && grep git RELEASE 2> /dev/null >/dev/null) ; then
- revision=$(cd "$1" && git describe --tags --match N 2> /dev/null)
- else
- revision=$(cd "$1" && git describe --tags --always 2> /dev/null)
- fi
--fi
-+ fi
-+
-+ # Shallow Git clones (--depth) do not have the N tag:
-+ # use 'git-YYYY-MM-DD-hhhhhhh'.
-+ test "$revision" || revision=$(cd "$1" &&
-+ git log -1 --pretty=format:"git-%cd-%h" --date=short 2> /dev/null)
-
--# Shallow Git clones (--depth) do not have the N tag:
--# use 'git-YYYY-MM-DD-hhhhhhh'.
--test "$revision" || revision=$(cd "$1" &&
-- git log -1 --pretty=format:"git-%cd-%h" --date=short 2> /dev/null)
--
--# Snapshots from gitweb are in a directory called ffmpeg-hhhhhhh or
--# ffmpeg-HEAD-hhhhhhh.
--if [ -z "$revision" ]; then
-- srcdir=$(cd "$1" && pwd)
-- case "$srcdir" in
-- */ffmpeg-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
-- git_hash="${srcdir##*-}";;
-- */ffmpeg-HEAD-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
-- git_hash="${srcdir##*-}";;
-- esac
-+ # Snapshots from gitweb are in a directory called ffmpeg-hhhhhhh or
-+ # ffmpeg-HEAD-hhhhhhh.
-+ if [ -z "$revision" ]; then
-+ srcdir=$(cd "$1" && pwd)
-+ case "$srcdir" in
-+ */ffmpeg-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
-+ git_hash="${srcdir##*-}";;
-+ */ffmpeg-HEAD-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f])
-+ git_hash="${srcdir##*-}";;
-+ esac
-+ fi
- fi
-
- # no revision number found
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-100-Speed_up_wtv_index_creation.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-100-Speed_up_wtv_index_creation.patch
deleted file mode 100644
index d829898294..0000000000
--- a/packages/multimedia/ffmpeg/patches/ffmpeg-100-Speed_up_wtv_index_creation.patch
+++ /dev/null
@@ -1,47 +0,0 @@
-commit 0e7427498cb1131671f6fe9d054245ae7e5a36f5
-Author: popcornmix
-Date: Tue Mar 25 19:43:07 2014 +0000
-
- [ffmpeg] Speed up wtv index creation
-
- The index creation is O(N^2) with number of entries (typically thousands).
- On a Pi this can take more than 60 seconds to execute for a recording of a few hours.
-
- By replacing with an O(N) loop, this takes virtually zero time
-
-diff --git a/libavformat/wtvdec.c b/libavformat/wtvdec.c
-index e423370..70898bd 100644
---- a/libavformat/wtvdec.c
-+++ b/libavformat/wtvdec.c
-@@ -980,21 +980,23 @@ static int read_header(AVFormatContext *s)
- pb = wtvfile_open(s, root, root_size, ff_timeline_table_0_entries_Events_le16);
- if (pb) {
- int i;
-+ AVIndexEntry *e = wtv->index_entries;
-+ AVIndexEntry *e_end = wtv->index_entries + wtv->nb_index_entries - 1;
-+ uint64_t last_position = 0;
- while (1) {
- uint64_t frame_nb = avio_rl64(pb);
- uint64_t position = avio_rl64(pb);
-+ while (frame_nb > e->size && e <= e_end) {
-+ e->pos = last_position;
-+ e++;
-+ }
- if (avio_feof(pb))
- break;
-- for (i = wtv->nb_index_entries - 1; i >= 0; i--) {
-- AVIndexEntry *e = wtv->index_entries + i;
-- if (frame_nb > e->size)
-- break;
-- if (position > e->pos)
-- e->pos = position;
-- }
-+ last_position = position;
- }
-+ e_end->pos = last_position;
- wtvfile_close(pb);
-- st->duration = wtv->index_entries[wtv->nb_index_entries - 1].timestamp;
-+ st->duration = e_end->timestamp;
- }
- }
- }
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-901-upstream.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-901-upstream.patch
deleted file mode 100644
index 203132fe78..0000000000
--- a/packages/multimedia/ffmpeg/patches/ffmpeg-901-upstream.patch
+++ /dev/null
@@ -1,23 +0,0 @@
-From 101dcdc12659e7fc2ddc1393992e2b431e2c4da1 Mon Sep 17 00:00:00 2001
-From: Hendrik Leppkes
-Date: Fri, 22 Jan 2016 13:50:42 +0100
-Subject: [PATCH] dxva2_h264: fix reference field marking in long slice struct
-
-Fixes artifacts in interlaced decoding on old Intel GPUs.
----
- libavcodec/dxva2_h264.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
-diff --git a/libavcodec/dxva2_h264.c b/libavcodec/dxva2_h264.c
-index eb5ecd1..242a79e 100644
---- a/libavcodec/dxva2_h264.c
-+++ b/libavcodec/dxva2_h264.c
-@@ -248,7 +248,7 @@ static void fill_slice_long(AVCodecContext *avctx, DXVA_Slice_H264_Long *slice,
- else
- index = get_refpic_index(pp, ff_dxva2_get_surface_index(avctx, ctx, r->f));
- fill_picture_entry(&slice->RefPicList[list][i], index,
-- r->reference == PICT_BOTTOM_FIELD);
-+ sl->ref_list[list][i].reference == PICT_BOTTOM_FIELD);
- for (plane = 0; plane < 3; plane++) {
- int w, o;
- if (plane == 0 && sl->luma_weight_flag[list]) {
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-101-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1000-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch
similarity index 99%
rename from packages/multimedia/ffmpeg/patches/ffmpeg-101-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch
rename to packages/multimedia/ffmpeg/patches/ffmpeg-99.1000-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch
index 4cb8dd8fc4..0e814fa3c0 100644
--- a/packages/multimedia/ffmpeg/patches/ffmpeg-101-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1000-mpeg4video-Signal-unsupported-GMC-with-more-than-one.patch
@@ -46,3 +46,4 @@ index 9bf33dd..0b5d3b9 100644
--
1.9.1
+
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-99.1001-hevcdsp_ARM_NEON_optimized_epel_functions.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1001-hevcdsp_ARM_NEON_optimized_epel_functions.patch
new file mode 100644
index 0000000000..d19984b4de
--- /dev/null
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1001-hevcdsp_ARM_NEON_optimized_epel_functions.patch
@@ -0,0 +1,410 @@
+From 29c3327a0d72a7e872ff170363cfe5ed13bca5d0 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Tue, 22 Dec 2015 18:10:24 +0000
+Subject: [PATCH] hevcdsp: ARM NEON optimized epel functions
+
+---
+ libavcodec/arm/Makefile | 1 +
+ libavcodec/arm/hevcdsp_epel_neon.S | 334 +++++++++++++++++++++++++++++++++++++
+ libavcodec/arm/hevcdsp_init_neon.c | 23 +++
+ 3 files changed, 358 insertions(+)
+ create mode 100644 libavcodec/arm/hevcdsp_epel_neon.S
+
+diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
+index cdd35b0..6051ec8 100644
+--- a/libavcodec/arm/Makefile
++++ b/libavcodec/arm/Makefile
+@@ -131,6 +131,7 @@ NEON-OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_neon.o \
+ arm/synth_filter_neon.o
+ NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \
+ arm/hevcdsp_deblock_neon.o \
++ arm/hevcdsp_epel_neon.o \
+ arm/hevcdsp_idct_neon.o \
+ arm/hevcdsp_qpel_neon.o
+ NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o
+diff --git a/libavcodec/arm/hevcdsp_epel_neon.S b/libavcodec/arm/hevcdsp_epel_neon.S
+new file mode 100644
+index 0000000..516ae5b
+--- /dev/null
++++ b/libavcodec/arm/hevcdsp_epel_neon.S
+@@ -0,0 +1,334 @@
++/*
++ * Copyright (c) 2014 - 2015 Seppo Tomperi
++ *
++ * This file is part of FFmpeg.
++ *
++ * FFmpeg is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * FFmpeg is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with FFmpeg; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include "libavutil/arm/asm.S"
++#include "neon.S"
++
++#define MAX_PB_SIZE #64
++
++.macro vextin_d4
++ vld1.8 {q10}, [r1], r2
++ vmov d16, d20
++ vext.8 d17, d20, d21, #1
++ vext.8 d18, d20, d21, #2
++ vext.8 d19, d20, d21, #3
++.endm
++
++.macro vextin_d4_8
++ vld1.8 d16, [r1], r2
++ vext.8 d17, d16, d16, #1
++ vext.8 d18, d16, d16, #2
++ vext.8 d19, d16, d16, #3
++.endm
++
++.macro load_coeffs_16b coeffs
++ ldr \coeffs, [\coeffs]
++ vdup.i8 d0, \coeffs
++ lsr \coeffs, #8
++ vdup.i8 d1, \coeffs
++ lsr \coeffs, #8
++ vdup.i8 d2, \coeffs
++ lsr \coeffs, #8
++ vdup.i8 d3, \coeffs
++.endm
++
++.macro epel_filter_16b out=q12
++ vmull.u8 q3, d16, d0
++ vmull.u8 q11, d19, d3
++ vmull.u8 \out, d17, d1
++ vmull.u8 q10, d18, d2
++ vadd.s16 q3, q11
++ vadd.s16 \out, q10
++ vsub.s16 \out, q3
++.endm
++
++.macro load_coeffs_32b coeffs
++ ldr \coeffs, [\coeffs]
++ vmov.i64 d4, #0
++ vmov.8 d4[0], \coeffs
++ lsr \coeffs, #8
++ vmov.8 d4[2], \coeffs
++ lsr \coeffs, #8
++ vmov.8 d4[4], \coeffs
++ lsr \coeffs, #8
++ vmov.8 d4[6], \coeffs
++.endm
++
++.macro epel_filter_32b
++ vmull.s16 q3, d24, d4[0] //q12
++ vmull.s16 q4, d25, d4[0]
++ vmull.s16 q5, d30, d4[3] //q15
++ vmull.s16 q6, d31, d4[3]
++
++ vmull.s16 q7, d26, d4[1] // q13
++ vmull.s16 q8, d27, d4[1]
++ vmull.s16 q9, d28, d4[2] // q14
++ vmull.s16 q10, d29, d4[2]
++ vadd.s32 q3, q5
++ vadd.s32 q4, q6
++ vadd.s32 q7, q9
++ vadd.s32 q8, q10
++ vsub.s32 q7, q3
++ vsub.s32 q8, q4
++ vqshrn.s32 d6, q7, #6
++ vqshrn.s32 d7, q8, #6
++.endm
++
++.macro epel_filter_32b_4
++ vmull.s16 q3, d24, d4[0] //q12
++ vmull.s16 q5, d30, d4[3] //q15
++ vmull.s16 q7, d26, d4[1] // q13
++ vmull.s16 q9, d28, d4[2] // q14
++ vadd.s32 q3, q5
++ vadd.s32 q7, q9
++ vsub.s32 q7, q3
++ vqshrn.s32 d6, q7, #6
++.endm
++
++function ff_hevc_put_epel_h_neon_8, export=1
++ push {r4-r7}
++ mov r4, MAX_PB_SIZE
++ ldr r7, [sp, #16] // mx
++ ldr r5, [sp, #24] // width
++ sub r7, #1
++ lsl r7, #2
++ vpush {d8-d15}
++ adrl r12, epel_coeffs
++ add r7, r12
++ sub r1, #1
++ lsl r4, #1
++ load_coeffs_16b r7
++ mov r12, r3
++ mov r6, r0
++ mov r7, r1
++ cmp r5, #6
++ bgt 8f
++ cmp r5, #4
++ blt 2f
++ b 4f
++8: subs r3, #1
++ pld [r1]
++ vextin_d4
++ epel_filter_16b
++ vst1.16 {q12}, [r0], r4
++ bne 8b
++ subs r5, #8
++ beq 99f
++ mov r3, r12
++ add r6, #16
++ mov r0, r6
++ add r7, #8
++ mov r1, r7
++ cmp r5, #4
++ bgt 8b
++4: subs r3, #1
++ pld [r1]
++ vextin_d4_8
++ epel_filter_16b
++ vst1.16 d24, [r0], r4
++ bne 4b
++ subs r5, #4
++ beq 99f
++ mov r3, r12
++ add r6, #8
++ mov r0, r6
++ add r7, #4
++ mov r1, r7
++2: subs r3, #1
++ pld [r1]
++ vextin_d4_8
++ epel_filter_16b
++ vst1.32 d24[0], [r0], r4
++ bne 2b
++99: vpop {d8-d15}
++ pop {r4-r7}
++ bx lr
++endfunc
++
++function ff_hevc_put_epel_v_neon_8, export=1
++ push {r4-r7}
++ mov r4, MAX_PB_SIZE
++ ldr r7, [sp, #20] // my
++ ldr r5, [sp, #24] // width
++ sub r7, #1
++ lsl r7, #2
++ vpush {d8-d15}
++ adrl r12, epel_coeffs
++ add r7, r12
++ load_coeffs_16b r7
++ sub r1, r2
++ lsl r4, #1
++ mov r12, r3
++ mov r6, r0
++ mov r7, r1
++0: pld [r1]
++ vld1.8 {d16}, [r1], r2
++ pld [r1]
++ vld1.8 {d17}, [r1], r2
++ pld [r1]
++ vld1.8 {d18}, [r1], r2
++ cmp r5, #6
++ bgt 8f
++ cmp r5, #4
++ blt 2f
++ b 4f
++8: pld [r1]
++ vld1.8 {d19}, [r1], r2
++ subs r3, #1
++ epel_filter_16b
++ vst1.16 {q12}, [r0], r4
++ vmov d16, d17
++ vmov d17, d18
++ vmov d18, d19
++ bne 8b
++ subs r5, #8
++ beq 99f
++ mov r3, r12
++ add r6, #16
++ mov r0, r6
++ add r7, #8
++ mov r1, r7
++ b 0b
++4: pld [r1]
++ vld1.8 {d19}, [r1], r2
++ subs r3, #1
++ epel_filter_16b
++ vst1.16 d24, [r0], r4
++ vmov d16, d17
++ vmov d17, d18
++ vmov d18, d19
++ bne 4b
++ subs r5, #4
++ beq 99f
++ mov r3, r12
++ add r6, #8
++ mov r0, r6
++ add r7, #4
++ mov r1, r7
++ b 0b
++2: pld [r1]
++ vld1.8 {d19}, [r1], r2
++ subs r3, #1
++ epel_filter_16b
++ vst1.32 d24[0], [r0], r4
++ vmov d16, d17
++ vmov d17, d18
++ vmov d18, d19
++ bne 2b
++99: vpop {d8-d15}
++ pop {r4-r7}
++ bx lr
++endfunc
++
++function ff_hevc_put_epel_hv_neon_8, export=1
++ push {r4-r7}
++ mov r4, MAX_PB_SIZE
++ ldr r6, [sp, #16] // mx
++ ldr r7, [sp, #20] // my
++ ldr r5, [sp, #24] // width
++ sub r7, #1
++ lsl r7, #2
++ vpush {d8-d15}
++ adrl r12, epel_coeffs
++ sub r6, #1
++ lsl r6, #2
++ add r6, r12 // mx epel coeff offset
++ add r7, r12
++ sub r1, #1
++ sub r1, r2
++ lsl r4, #1
++ load_coeffs_16b r6
++ load_coeffs_32b r7
++ mov r12, r3
++ mov r6, r0
++ mov r7, r1
++0: pld [r1]
++ vextin_d4
++ epel_filter_16b q12
++ pld [r1]
++ vextin_d4
++ epel_filter_16b q13
++ pld [r1]
++ vextin_d4
++ epel_filter_16b q14
++ cmp r5, #6
++ bgt 8f
++ cmp r5, #4
++ blt 2f
++ b 4f
++8: pld [r1]
++ vextin_d4
++ epel_filter_16b q15
++ subs r3, #1
++ epel_filter_32b
++ vst1.16 {q3}, [r0], r4
++ vmov q12, q13
++ vmov q13, q14
++ vmov q14, q15
++ bne 8b
++ subs r5, #8
++ beq 99f
++ mov r3, r12
++ add r6, #16
++ mov r0, r6
++ add r7, #8
++ mov r1, r7
++ b 0b
++4: pld [r1]
++ vextin_d4_8
++ epel_filter_16b q15
++ subs r3, #1
++ epel_filter_32b_4
++ vst1.16 d6, [r0], r4
++ vmov q12, q13
++ vmov q13, q14
++ vmov q14, q15
++ bne 4b
++ subs r5, #4
++ beq 99f
++ mov r3, r12
++ add r6, #8
++ mov r0, r6
++ add r7, #4
++ mov r1, r7
++ b 0b
++2: pld [r1]
++ vextin_d4_8
++ epel_filter_16b q15
++ subs r3, #1
++ epel_filter_32b_4
++ vst1.32 d6[0], [r0], r4
++ vmov q12, q13
++ vmov q13, q14
++ vmov q14, q15
++ bne 2b
++99: vpop {d8-d15}
++ pop {r4-r7}
++ bx lr
++endfunc
++
++epel_coeffs:
++ .byte 2, 58, 10, 2
++ .byte 4, 54, 16, 2
++ .byte 6, 46, 28, 4
++ .byte 4, 36, 36, 4
++ .byte 4, 28, 46, 6
++ .byte 2, 16, 54, 4
++ .byte 2, 10, 58, 2
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index 5591807..733ff08 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -58,6 +58,15 @@ PUT_PIXELS(ff_hevc_put_pixels_w32_neon_8);
+ PUT_PIXELS(ff_hevc_put_pixels_w48_neon_8);
+ PUT_PIXELS(ff_hevc_put_pixels_w64_neon_8);
+ #undef PUT_PIXELS
++void ff_hevc_put_epel_h_neon_8(int16_t *dst, uint8_t *src,
++ ptrdiff_t srcstride, int height,
++ intptr_t mx, intptr_t my, int width);
++void ff_hevc_put_epel_v_neon_8(int16_t *dst, uint8_t *src,
++ ptrdiff_t srcstride, int height,
++ intptr_t mx, intptr_t my, int width);
++void ff_hevc_put_epel_hv_neon_8(int16_t *dst, uint8_t *src,
++ ptrdiff_t srcstride, int height,
++ intptr_t mx, intptr_t my, int width);
+
+ static void (*put_hevc_qpel_neon[4][4])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
+ int height, int width);
+@@ -201,7 +210,21 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
+ c->put_hevc_qpel_bi[x][1][0] = ff_hevc_put_qpel_bi_neon_wrapper;
+ c->put_hevc_qpel_bi[x][0][1] = ff_hevc_put_qpel_bi_neon_wrapper;
+ c->put_hevc_qpel_bi[x][1][1] = ff_hevc_put_qpel_bi_neon_wrapper;
++ c->put_hevc_epel[x][1][0] = ff_hevc_put_epel_v_neon_8;
++ c->put_hevc_epel[x][0][1] = ff_hevc_put_epel_h_neon_8;
++ c->put_hevc_epel[x][1][1] = ff_hevc_put_epel_hv_neon_8;
+ }
++ c->put_hevc_epel[0][0][0] = ff_hevc_put_pixels_w2_neon_8;
++ c->put_hevc_epel[1][0][0] = ff_hevc_put_pixels_w4_neon_8;
++ c->put_hevc_epel[2][0][0] = ff_hevc_put_pixels_w6_neon_8;
++ c->put_hevc_epel[3][0][0] = ff_hevc_put_pixels_w8_neon_8;
++ c->put_hevc_epel[4][0][0] = ff_hevc_put_pixels_w12_neon_8;
++ c->put_hevc_epel[5][0][0] = ff_hevc_put_pixels_w16_neon_8;
++ c->put_hevc_epel[6][0][0] = ff_hevc_put_pixels_w24_neon_8;
++ c->put_hevc_epel[7][0][0] = ff_hevc_put_pixels_w32_neon_8;
++ c->put_hevc_epel[8][0][0] = ff_hevc_put_pixels_w48_neon_8;
++ c->put_hevc_epel[9][0][0] = ff_hevc_put_pixels_w64_neon_8;
++
+ c->put_hevc_qpel[0][0][0] = ff_hevc_put_pixels_w2_neon_8;
+ c->put_hevc_qpel[1][0][0] = ff_hevc_put_pixels_w4_neon_8;
+ c->put_hevc_qpel[2][0][0] = ff_hevc_put_pixels_w6_neon_8;
+--
+2.5.0
+
+
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-99.1002-added_ARM_NEON_optimized_SAO_patches.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1002-added_ARM_NEON_optimized_SAO_patches.patch
new file mode 100644
index 0000000000..f090c38c7e
--- /dev/null
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1002-added_ARM_NEON_optimized_SAO_patches.patch
@@ -0,0 +1,3329 @@
+From b0cb307c253d2c9f4b94a54dfc74ddb83af984cc Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Mon, 8 Dec 2014 13:24:40 +0200
+Subject: [PATCH 1/9] added ARM NEON optimized SAO band offset
+
+---
+ libavcodec/arm/Makefile | 3 +-
+ libavcodec/arm/hevcdsp_init_neon.c | 47 +++++++++
+ libavcodec/arm/hevcdsp_sao_neon.S | 204 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 253 insertions(+), 1 deletion(-)
+ create mode 100644 libavcodec/arm/hevcdsp_sao_neon.S
+
+diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
+index 6051ec8..093a2e8 100644
+--- a/libavcodec/arm/Makefile
++++ b/libavcodec/arm/Makefile
+@@ -133,7 +133,8 @@ NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \
+ arm/hevcdsp_deblock_neon.o \
+ arm/hevcdsp_epel_neon.o \
+ arm/hevcdsp_idct_neon.o \
+- arm/hevcdsp_qpel_neon.o
++ arm/hevcdsp_qpel_neon.o \
++ arm/hevcdsp_sao_neon.o
+ NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o
+ NEON-OBJS-$(CONFIG_RV40_DECODER) += arm/rv34dsp_neon.o \
+ arm/rv40dsp_neon.o
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index 733ff08..69e2b2c 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -22,6 +22,7 @@
+ #include "libavutil/arm/cpu.h"
+ #include "libavcodec/hevcdsp.h"
+ #include "hevcdsp_arm.h"
++#include "../bit_depth_template.c"
+
+ void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+ void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+@@ -43,6 +44,11 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs,
+ void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs,
+ ptrdiff_t stride);
+
++void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
++void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
++void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
++void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
++
+ #define PUT_PIXELS(name) \
+ void name(int16_t *dst, uint8_t *src, \
+ ptrdiff_t srcstride, int height, \
+@@ -151,6 +157,44 @@ void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t
+ put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, src2, MAX_PB_SIZE);
+ }
+
++static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src,
++ int16_t *sao_offset_val, int sao_left_class, int width, int height)
++{
++ pixel *dst = (pixel *)_dst;
++ pixel *src = (pixel *)_src;
++ int8_t offset_table[32] = { 0 };
++ int k, y, x;
++ int shift = 3; // BIT_DEPTH - 5
++
++ stride_src /= sizeof(pixel);
++ stride_dst /= sizeof(pixel);
++
++ for (k = 0; k < 4; k++)
++ offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];
++
++ switch(width){
++ case 8:
++ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ break;
++ case 16:
++ ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ break;
++ case 32:
++ ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ break;
++ case 64:
++ ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ break;
++ default:
++ for (y = 0; y < height; y++) {
++ for (x = 0; x < width; x++)
++ dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]);
++ dst += stride_dst;
++ src += stride_src;
++ }
++ }
++}
++
+ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
+ {
+ if (bit_depth == 8) {
+@@ -170,6 +214,9 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
+ c->transform_add[2] = ff_hevc_transform_add_16x16_neon_8;
+ c->transform_add[3] = ff_hevc_transform_add_32x32_neon_8;
+ c->idct_4x4_luma = ff_hevc_transform_luma_4x4_neon_8;
++ for (x = 0; x < sizeof c->sao_band_filter / sizeof *c->sao_band_filter; x++) {
++ c->sao_band_filter[x] = ff_hevc_sao_band_neon_wrapper;
++ }
+ put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8;
+ put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8;
+ put_hevc_qpel_neon[3][0] = ff_hevc_put_qpel_v3_neon_8;
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+new file mode 100644
+index 0000000..1f0ad64
+--- /dev/null
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -0,0 +1,204 @@
++/*
++ * Copyright (c) 2014 Seppo Tomperi
++ *
++ * This file is part of FFmpeg.
++ *
++ * FFmpeg is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * FFmpeg is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with FFmpeg; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#include "libavutil/arm/asm.S"
++#include "neon.S"
++
++function ff_hevc_sao_band_w8_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // offset_table
++ vpush {d8-d15}
++ vld1.8 {q0, q1}, [r5] // offset table
++
++1: subs r4, #1
++ vld1.8 {d24}, [r1], r3
++ vshr.u8 d16, d24, #3
++ vtbl.8 d16, {q0, q1}, d16
++ vmovl.s8 q2, d16
++ vmovl.u8 q6, d24
++ vadd.s16 q2, q6
++ vqmovun.s16 d4, q2
++ vst1.8 {d4}, [r0], r2
++ bne 1b
++
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_band_w16_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // offset_table
++ vpush {d8-d15}
++ vld1.8 {q0, q1}, [r5] // offset table
++
++1: subs r4, #1
++ vld1.8 {q12}, [r1], r3
++
++ vshr.u8 q8, q12, #3
++
++ vtbl.8 d16, {q0, q1}, d16
++ vtbl.8 d17, {q0, q1}, d17
++
++ vmovl.s8 q2, d16
++ vmovl.s8 q3, d17
++
++ vmovl.u8 q6, d24
++ vmovl.u8 q7, d25
++
++ vadd.s16 q2, q6
++ vadd.s16 q3, q7
++
++ vqmovun.s16 d4, q2
++ vqmovun.s16 d5, q3
++
++ vstm.8 r0, {q2}
++ add r0, r2
++ bne 1b
++
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_band_w32_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // offset_table
++ vpush {d8-d15}
++ vld1.8 {q0, q1}, [r5] // offset table
++
++1: subs r4, #1
++ vld1.8 {q12-q13}, [r1], r3
++
++ vshr.u8 q8, q12, #3
++ vshr.u8 q9, q13, #3
++
++ vtbl.8 d16, {q0, q1}, d16
++ vtbl.8 d17, {q0, q1}, d17
++ vtbl.8 d18, {q0, q1}, d18
++ vtbl.8 d19, {q0, q1}, d19
++
++ vmovl.s8 q2, d16
++ vmovl.s8 q3, d17 // q8 free
++ vmovl.s8 q4, d18
++ vmovl.s8 q5, d19 // q9 free
++
++ vmovl.u8 q6, d24
++ vmovl.u8 q7, d25 // q12 free
++ vmovl.u8 q8, d26
++ vmovl.u8 q9, d27 // q13 free
++
++ vadd.s16 q2, q6
++ vadd.s16 q3, q7
++ vadd.s16 q4, q8
++ vadd.s16 q5, q9
++
++ vqmovun.s16 d4, q2
++ vqmovun.s16 d5, q3
++ vqmovun.s16 d6, q4 // q4 free
++ vqmovun.s16 d7, q5 // q5 free
++
++ vst1.8 {q2-q3}, [r0], r2
++ bne 1b
++
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_band_w64_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // offset_table
++ vpush {d8-d15}
++ vld1.8 {q0, q1}, [r5] // offset table
++
++1: subs r4, #1
++ vld1.8 {q12-q13}, [r1]!
++ vld1.8 {q14-q15}, [r1], r3
++ sub r1, #32
++
++ vshr.u8 q8, q12, #3
++ vshr.u8 q9, q13, #3
++ vshr.u8 q10, q14, #3
++ vshr.u8 q11, q15, #3
++
++ vtbl.8 d16, {q0, q1}, d16
++ vtbl.8 d17, {q0, q1}, d17
++ vtbl.8 d18, {q0, q1}, d18
++ vtbl.8 d19, {q0, q1}, d19
++ vtbl.8 d20, {q0, q1}, d20
++ vtbl.8 d21, {q0, q1}, d21
++ vtbl.8 d22, {q0, q1}, d22
++ vtbl.8 d23, {q0, q1}, d23
++
++ vmovl.s8 q2, d16
++ vmovl.s8 q3, d17 // q8 free
++ vmovl.s8 q4, d18
++ vmovl.s8 q5, d19 // q9 free
++
++ vmovl.u8 q6, d24
++ vmovl.u8 q7, d25 // q12 free
++ vmovl.u8 q8, d26
++ vmovl.u8 q9, d27 // q13 free
++
++ vadd.s16 q2, q6
++ vadd.s16 q3, q7
++ vadd.s16 q4, q8
++ vadd.s16 q5, q9
++
++ vqmovun.s16 d4, q2
++ vqmovun.s16 d5, q3
++ vqmovun.s16 d6, q4 // q4 free
++ vqmovun.s16 d7, q5 // q5 free
++
++ // free q4 -q9, q12 - q13
++ vmovl.s8 q4, d20
++ vmovl.s8 q5, d21 // q10 free
++ vmovl.s8 q6, d22
++ vmovl.s8 q7, d23 // q11 free
++
++ vmovl.u8 q8, d28
++ vmovl.u8 q9, d29 // q14 free
++ vmovl.u8 q10, d30
++ vmovl.u8 q11, d31 // q15 free
++
++ vadd.s16 q4, q8
++ vadd.s16 q5, q9
++ vadd.s16 q6, q10
++ vadd.s16 q7, q11
++
++ vqmovun.s16 d8, q4
++ vqmovun.s16 d9, q5
++ vqmovun.s16 d10, q6
++ vqmovun.s16 d11, q7
++
++ vstm.8 r0, {q2-q5}
++ add r0, r2
++ bne 1b
++
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
+--
+2.5.0
+
+
+From 8429b1de64bb871d57651ecfe3b084e2dfe0af51 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Wed, 27 May 2015 18:10:20 +0100
+Subject: [PATCH 2/9] added NEON optimized sao edge for eo1 width 64
+
+---
+ libavcodec/arm/hevcdsp_init_neon.c | 47 ++++++++++++
+ libavcodec/arm/hevcdsp_sao_neon.S | 147 +++++++++++++++++++++++++++++++++++++
+ 2 files changed, 194 insertions(+)
+
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index 69e2b2c..c7b5404 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -22,6 +22,7 @@
+ #include "libavutil/arm/cpu.h"
+ #include "libavcodec/hevcdsp.h"
+ #include "hevcdsp_arm.h"
++#include "libavcodec/avcodec.h"
+ #include "../bit_depth_template.c"
+
+ void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+@@ -48,6 +49,7 @@ void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_d
+ void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
+ void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
+ void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
++void ff_hevc_sao_edge_eo1_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
+
+ #define PUT_PIXELS(name) \
+ void name(int16_t *dst, uint8_t *src, \
+@@ -195,6 +197,50 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
+ }
+ }
+
++#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
++static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t *_src /* align 32 */, ptrdiff_t stride_dst,
++ int16_t *_sao_offset_val, int eo, int width, int height)
++{
++ static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };
++ static const int8_t pos[4][2][2] = {
++ { { -1, 0 }, { 1, 0 } }, // horizontal
++ { { 0, -1 }, { 0, 1 } }, // vertical
++ { { -1, -1 }, { 1, 1 } }, // 45 degree
++ { { 1, -1 }, { -1, 1 } }, // 135 degree
++ };
++ int8_t sao_offset_val[8]; // padding of 3 for vld
++ ptrdiff_t stride_src = (2*MAX_PB_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
++ pixel *dst = (pixel *)_dst;
++ pixel *src = (pixel *)_src;
++ int a_stride, b_stride;
++ int x, y;
++
++ for (x = 0; x < 5; x++) {
++ sao_offset_val[x] = _sao_offset_val[x];
++ }
++
++ stride_src /= sizeof(pixel);
++ stride_dst /= sizeof(pixel);
++
++ if (eo == 1 && width == 64) {
++ ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ } else {
++ a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;
++ b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;
++ for (y = 0; y < height; y++) {
++ for (x = 0; x < width; x++) {
++ int diff0 = CMP(src[x], src[x + a_stride]);
++ int diff1 = CMP(src[x], src[x + b_stride]);
++ int offset_val = edge_idx[2 + diff0 + diff1];
++ dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);
++ }
++ src += stride_src;
++ dst += stride_dst;
++ }
++ }
++}
++#undef CMP
++
+ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
+ {
+ if (bit_depth == 8) {
+@@ -216,6 +262,7 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
+ c->idct_4x4_luma = ff_hevc_transform_luma_4x4_neon_8;
+ for (x = 0; x < sizeof c->sao_band_filter / sizeof *c->sao_band_filter; x++) {
+ c->sao_band_filter[x] = ff_hevc_sao_band_neon_wrapper;
++ c->sao_edge_filter[x] = ff_hevc_sao_edge_neon_wrapper;
+ }
+ put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8;
+ put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8;
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index 1f0ad64..5ec2de9 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -202,3 +202,150 @@ function ff_hevc_sao_band_w64_neon_8, export=1
+ bx lr
+ endfunc
+
++function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x02
++ vpush {d8-d15}
++1: subs r4, #1
++ // load a
++ sub r1, r3
++ vld1.8 {q0-q1}, [r1]!
++ vld1.8 {q2-q3}, [r1], r3
++ sub r1, #32
++ // load c
++ vld1.8 {q4-q5}, [r1]!
++ vld1.8 {q6-q7}, [r1], r3
++ sub r1, #32
++ // load b
++ vld1.8 {q8-q9}, [r1]!
++ vld1.8 {q10-q11}, [r1], r3
++ sub r1, #32
++
++ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
++ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
++ vcgt.u8 q13, q5, q1
++ vcgt.u8 q1, q1, q5
++ vcgt.u8 q14, q6, q2
++ vcgt.u8 q2, q2, q6
++ vcgt.u8 q15, q7, q3
++ vcgt.u8 q3, q3, q7
++
++ vsub.s8 q12, q0, q12 // diff0
++ vsub.s8 q13, q1, q13
++ vsub.s8 q14, q2, q14
++ vsub.s8 q15, q3, q15
++
++ vcgt.u8 q0, q4, q8 // c > b
++ vcgt.u8 q8, q8, q4 // b > c
++ vcgt.u8 q1, q5, q9
++ vcgt.u8 q9, q9, q5
++ vcgt.u8 q2, q6, q10
++ vcgt.u8 q10, q10, q6
++ vcgt.u8 q3, q7, q11
++ vcgt.u8 q11, q11, q7
++
++ vsub.s8 q0, q8, q0 // diff1
++ vsub.s8 q1, q9, q1
++ vsub.s8 q2, q10, q2
++ vsub.s8 q3, q11, q3
++
++ veor.u8 q8, q8 // zero register
++ vdup.s8 q9, r6 // 2 to all elements
++ add r6, #1
++ vdup.s8 q10, r6 // 3 to all elements
++ sub r6, #1
++
++ vadd.s8 q0, q12 //diff0 + diff1
++ vadd.s8 q1, q13
++ vadd.s8 q2, q14
++ vadd.s8 q3, q15
++
++ vcgt.s8 q4, q0, q8 // diff0 + diff1 > 0
++ vcgt.s8 q5, q1, q8
++ vcgt.s8 q6, q2, q8
++ vcgt.s8 q7, q3, q8
++
++ vclt.s8 q11, q0, q8 // diff0 + diff1 < 0
++ vclt.s8 q12, q1, q8
++ vclt.s8 q13, q2, q8
++ vclt.s8 q14, q3, q8
++
++ vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
++ vand.8 q15, q8, q4
++ vadd.s8 q8, q0, q10 // diff0 + diff1 + 3
++ vand.8 q8, q8, q11
++ vadd.s8 q0, q15, q8 // offset_idx
++
++ vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
++ vand.8 q15, q8, q5
++ vadd.s8 q8, q1, q10 // diff0 + diff1 + 3
++ vand.8 q8, q8, q12
++ vadd.s8 q1, q15, q8 // offset_idx
++
++ vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 + 2
++ vand.8 q15, q8, q6
++ vadd.s8 q8, q2, q10 // diff0 + diff1 + 2 + 3
++ vand.8 q8, q8, q13
++ vadd.s8 q2, q15, q8 // offset_idx
++
++ vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 + 2
++ vand.8 q15, q8, q7
++ vadd.s8 q8, q3, q10 // diff0 + diff1 + 2 + 3
++ vand.8 q8, q8, q14
++ vadd.s8 q3, q15, q8 // offset_idx
++ // TODO: load only once
++ vld1.8 d16, [r5]
++
++ vtbl.8 d0, {d16}, d0
++ vtbl.8 d1, {d16}, d1
++ vtbl.8 d2, {d16}, d2
++ vtbl.8 d3, {d16}, d3
++ vtbl.8 d4, {d16}, d4
++ vtbl.8 d5, {d16}, d5
++ vtbl.8 d6, {d16}, d6
++ vtbl.8 d7, {d16}, d7
++
++ // TODO: load only once
++ // load c again
++ sub r1, r3
++ sub r1, r3
++ vld1.8 {q4-q5}, [r1]!
++ vld1.8 {q6-q7}, [r1], r3
++ sub r1, #32
++
++ vmovl.u8 q8, d8
++ vmovl.u8 q9, d9
++ vmovl.u8 q10, d10
++ vmovl.u8 q11, d11
++ vmovl.u8 q12, d12
++ vmovl.u8 q13, d13
++ vmovl.u8 q14, d14
++ vmovl.u8 q15, d15
++
++ vaddw.s8 q8, d0
++ vaddw.s8 q9, d1
++ vaddw.s8 q10, d2
++ vaddw.s8 q11, d3
++ vaddw.s8 q12, d4
++ vaddw.s8 q13, d5
++ vaddw.s8 q14, d6
++ vaddw.s8 q15, d7
++
++ vqmovun.s16 d0, q8
++ vqmovun.s16 d1, q9
++ vqmovun.s16 d2, q10
++ vqmovun.s16 d3, q11
++ vqmovun.s16 d4, q12
++ vqmovun.s16 d5, q13
++ vqmovun.s16 d6, q14
++ vqmovun.s16 d7, q15
++
++ vstm r0, {q0-q3}
++ add r0, r2
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
+--
+2.5.0
+
+
+From 402e2bd1c5ad659c757bf9734abe6331904fb9e2 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Tue, 16 Dec 2014 16:28:25 +0200
+Subject: [PATCH 3/9] Added SAO edge offset for ARM NEON w32 and w64
+
+---
+ libavcodec/arm/hevcdsp_init_neon.c | 46 +++-
+ libavcodec/arm/hevcdsp_sao_neon.S | 510 +++++++++++++++++++++++++++++++------
+ 2 files changed, 474 insertions(+), 82 deletions(-)
+
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index c7b5404..c32940e 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -49,7 +49,16 @@ void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_d
+ void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
+ void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
+ void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
++
++void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
++void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
++void ff_hevc_sao_edge_eo2_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
++void ff_hevc_sao_edge_eo3_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
++
++void ff_hevc_sao_edge_eo0_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
+ void ff_hevc_sao_edge_eo1_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
++void ff_hevc_sao_edge_eo2_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
++void ff_hevc_sao_edge_eo3_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
+
+ #define PUT_PIXELS(name) \
+ void name(int16_t *dst, uint8_t *src, \
+@@ -222,9 +231,40 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
+ stride_src /= sizeof(pixel);
+ stride_dst /= sizeof(pixel);
+
+- if (eo == 1 && width == 64) {
+- ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
+- } else {
++ switch (width) {
++ case 32:
++ switch(eo) {
++ case 0:
++ ff_hevc_sao_edge_eo0_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ case 1:
++ ff_hevc_sao_edge_eo1_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ case 2:
++ ff_hevc_sao_edge_eo2_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ case 3:
++ ff_hevc_sao_edge_eo3_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ }
++ break;
++ case 64:
++ switch(eo) {
++ case 0:
++ ff_hevc_sao_edge_eo0_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ case 1:
++ ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ case 2:
++ ff_hevc_sao_edge_eo2_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ case 3:
++ ff_hevc_sao_edge_eo3_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
++ break;
++ }
++ break;
++ default:
+ a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;
+ b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;
+ for (y = 0; y < height; y++) {
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index 5ec2de9..4687012 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -202,27 +202,7 @@ function ff_hevc_sao_band_w64_neon_8, export=1
+ bx lr
+ endfunc
+
+-function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x02
+- vpush {d8-d15}
+-1: subs r4, #1
+- // load a
+- sub r1, r3
+- vld1.8 {q0-q1}, [r1]!
+- vld1.8 {q2-q3}, [r1], r3
+- sub r1, #32
+- // load c
+- vld1.8 {q4-q5}, [r1]!
+- vld1.8 {q6-q7}, [r1], r3
+- sub r1, #32
+- // load b
+- vld1.8 {q8-q9}, [r1]!
+- vld1.8 {q10-q11}, [r1], r3
+- sub r1, #32
+-
++.macro edge_w64_body
+ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
+ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
+ vcgt.u8 q13, q5, q1
+@@ -251,69 +231,61 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
+ vsub.s8 q2, q10, q2
+ vsub.s8 q3, q11, q3
+
+- veor.u8 q8, q8 // zero register
+- vdup.s8 q9, r6 // 2 to all elements
+- add r6, #1
+- vdup.s8 q10, r6 // 3 to all elements
+- sub r6, #1
+-
+ vadd.s8 q0, q12 //diff0 + diff1
+ vadd.s8 q1, q13
+ vadd.s8 q2, q14
+ vadd.s8 q3, q15
+
+- vcgt.s8 q4, q0, q8 // diff0 + diff1 > 0
+- vcgt.s8 q5, q1, q8
+- vcgt.s8 q6, q2, q8
+- vcgt.s8 q7, q3, q8
+-
+- vclt.s8 q11, q0, q8 // diff0 + diff1 < 0
+- vclt.s8 q12, q1, q8
+- vclt.s8 q13, q2, q8
+- vclt.s8 q14, q3, q8
+-
+- vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
+- vand.8 q15, q8, q4
+- vadd.s8 q8, q0, q10 // diff0 + diff1 + 3
+- vand.8 q8, q8, q11
+- vadd.s8 q0, q15, q8 // offset_idx
+-
+- vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
+- vand.8 q15, q8, q5
+- vadd.s8 q8, q1, q10 // diff0 + diff1 + 3
+- vand.8 q8, q8, q12
+- vadd.s8 q1, q15, q8 // offset_idx
+-
+- vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 + 2
+- vand.8 q15, q8, q6
+- vadd.s8 q8, q2, q10 // diff0 + diff1 + 2 + 3
+- vand.8 q8, q8, q13
+- vadd.s8 q2, q15, q8 // offset_idx
+-
+- vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 + 2
+- vand.8 q15, q8, q7
+- vadd.s8 q8, q3, q10 // diff0 + diff1 + 2 + 3
+- vand.8 q8, q8, q14
+- vadd.s8 q3, q15, q8 // offset_idx
+- // TODO: load only once
+- vld1.8 d16, [r5]
+-
+- vtbl.8 d0, {d16}, d0
+- vtbl.8 d1, {d16}, d1
+- vtbl.8 d2, {d16}, d2
+- vtbl.8 d3, {d16}, d3
+- vtbl.8 d4, {d16}, d4
+- vtbl.8 d5, {d16}, d5
+- vtbl.8 d6, {d16}, d6
+- vtbl.8 d7, {d16}, d7
+-
+- // TODO: load only once
+- // load c again
+- sub r1, r3
+- sub r1, r3
+- vld1.8 {q4-q5}, [r1]!
+- vld1.8 {q6-q7}, [r1], r3
+- sub r1, #32
++ vdup.s8 q9, r6 // 3 to all elements
++ sub r6, #1
++
++ vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
++ vclt.s8 q13, q1, #0
++ vclt.s8 q14, q2, #0
++ vclt.s8 q15, q3, #0
++
++ vadd.s8 q8, q0, q9 // diff0 + diff1 + 3
++ vadd.s8 q10, q1, q9
++ vand.8 q12, q8, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
++ vand.8 q13, q10, q13
++ vadd.s8 q8, q2, q9
++ vadd.s8 q10, q3, q9
++ vand.8 q14, q8, q14
++ vand.8 q15, q10, q15
++
++ vdup.s8 q9, r6 // 2 to all elements
++ add r6, #1
++
++ vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
++ vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
++ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
++ vcgt.s8 q10, q1, #0
++ vadd.s8 q0, q11, q12 // offset_idx
++
++ vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
++ vcgt.s8 q12, q2, #0
++ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
++ vadd.s8 q8, q2, q9 // diff0 + diff1 + 2
++ vadd.s8 q1, q11, q13
++
++ vand.8 q11, q8, q12 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
++ vcgt.s8 q10, q3, #0
++ vadd.s8 q2, q11, q14
++
++ vadd.s8 q8, q3, q9 // diff0 + diff1 + 2
++ vmov.32 d18[0], r7 // load offset table from general registers
++ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
++ vmov.32 d18[1], r5 // load rest of offset table
++ vadd.s8 q3, q11, q15
++
++ vtbl.8 d0, {d18}, d0
++ vtbl.8 d1, {d18}, d1
++ vtbl.8 d2, {d18}, d2
++ vtbl.8 d3, {d18}, d3
++ vtbl.8 d4, {d18}, d4
++ vtbl.8 d5, {d18}, d5
++ vtbl.8 d6, {d18}, d6
++ vtbl.8 d7, {d18}, d7
+
+ vmovl.u8 q8, d8
+ vmovl.u8 q9, d9
+@@ -344,8 +316,388 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
+
+ vstm r0, {q0-q3}
+ add r0, r2
++.endm
++
++.macro edge_w32_body
++ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
++ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
++ vcgt.u8 q13, q5, q1
++ vcgt.u8 q1, q1, q5
++
++ vsub.s8 q12, q0, q12 // diff0
++ vcgt.u8 q0, q4, q8 // c > b
++ vsub.s8 q13, q1, q13 // diff0 part 2
++
++ vcgt.u8 q6, q8, q4 // b > c
++ vcgt.u8 q1, q5, q9
++ vcgt.u8 q7, q9, q5
++
++ vsub.s8 q0, q6, q0 // diff1
++ vsub.s8 q1, q7, q1 // diff1 part 2
++ vadd.s8 q0, q12 //diff0 + diff1
++
++ vdup.s8 q7, r6 // 3 to all elements
++ sub r6, #1
++ vadd.s8 q1, q13
++
++ vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
++ vclt.s8 q13, q1, #0
++
++ vadd.s8 q6, q0, q7 // diff0 + diff1 + 3
++ vadd.s8 q10, q1, q7
++ vdup.s8 q7, r6 // 2 to all elements
++ add r6, #1
++ vand.8 q12, q6, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
++ vand.8 q13, q10, q13
++
++
++ vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
++ vadd.s8 q6, q0, q7 // diff0 + diff1 + 2
++ vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
++ vcgt.s8 q10, q1, #0
++ vadd.s8 q0, q11, q12 // offset_idx
++
++ vadd.s8 q6, q1, q7 // diff0 + diff1 + 2
++ vmov.32 d14[0], r7 // load offset table from general registers
++ vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
++ vmov.32 d14[1], r5 // load rest of offset table
++ vadd.s8 q1, q11, q13
++
++ vtbl.8 d0, {d14}, d0
++ vtbl.8 d1, {d14}, d1
++ vtbl.8 d2, {d14}, d2
++ vtbl.8 d3, {d14}, d3
++
++ vmovl.u8 q6, d8
++ vmovl.u8 q7, d9
++ vmovl.u8 q10, d10
++ vmovl.u8 q11, d11
++
++ vaddw.s8 q6, d0
++ vaddw.s8 q7, d1
++ vaddw.s8 q10, d2
++ vaddw.s8 q11, d3
++
++ vqmovun.s16 d0, q6
++ vqmovun.s16 d1, q7
++ vqmovun.s16 d2, q10
++ vqmovun.s16 d3, q11
++
++ vstm r0, {q0-q1}
++ add r0, r2
++.endm
++
++function ff_hevc_sao_edge_eo0_w64_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ ldr r5, [r5]
++ vpush {d8-d15}
++ sub r1, #8
++1: subs r4, #1
++ vld1.64 {q10-q11}, [r1]!
++ vld1.64 {q12-q13}, [r1]!
++ vld1.64 {q14}, [r1], r3
++ sub r1, #64
++ // load a
++ vext.8 q0, q10, q11, #7
++ vext.8 q1, q11, q12, #7
++ vext.8 q2, q12, q13, #7
++ vext.8 q3, q13, q14, #7
++ // load c
++ vext.8 q4, q10, q11, #8
++ vext.8 q5, q11, q12, #8
++ vext.8 q6, q12, q13, #8
++ vext.8 q7, q13, q14, #8
++ // load b
++ vext.8 q8, q10, q11, #9
++ vext.8 q9, q11, q12, #9
++ vext.8 q10, q12, q13, #9
++ vext.8 q11, q13, q14, #9
++ edge_w64_body
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ ldr r5, [r5]
++ vpush {d8-d15}
++ sub r1, r3
++ // load a
++ vld1.8 {q0-q1}, [r1]!
++ vld1.8 {q2-q3}, [r1], r3
++ sub r1, #32
++1: subs r4, #1
++ // load c
++ vld1.8 {q4-q5}, [r1]!
++ vld1.8 {q6-q7}, [r1], r3
++ sub r1, #32
++ // load b
++ vld1.8 {q8-q9}, [r1]!
++ vld1.8 {q10-q11}, [r1]
++ sub r1, #32
++ edge_w64_body
++ // copy c to a
++ vmov.64 q0, q4
++ vmov.64 q1, q5
++ vmov.64 q2, q6
++ vmov.64 q3, q7
+ bne 1b
+ vpop {d8-d15}
+ pop {r4-r8}
+ bx lr
+ endfunc
++
++function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ ldr r5, [r5]
++ vpush {d8-d15}
++1: sub r1, r3
++ // load a
++ // TODO: fix unaligned load
++ // don't reload a like in eo1
++ sub r1, #1
++ vld1.8 {q0-q1}, [r1]!
++ vld1.8 {q2-q3}, [r1], r3
++ sub r1, #31
++ subs r4, #1
++ // load c
++ vld1.8 {q4-q5}, [r1]!
++ vld1.8 {q6-q7}, [r1], r3
++ sub r1, #32
++ // load b
++ add r1, #1
++ vld1.8 {q8-q9}, [r1]!
++ vld1.8 {q10-q11}, [r1]
++ sub r1, #33
++ edge_w64_body
++ // copy c to a
++ vmov.64 q0, q4
++ vmov.64 q1, q5
++ vmov.64 q2, q6
++ vmov.64 q3, q7
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ ldr r5, [r5]
++ vpush {d8-d15}
++1: sub r1, r3
++ // load a
++ // TODO: fix unaligned load
++ // don't reload a like in eo1
++ add r1, #1
++ vld1.8 {q0-q1}, [r1]!
++ vld1.8 {q2-q3}, [r1], r3
++ sub r1, #33
++ subs r4, #1
++ // load c
++ vld1.8 {q4-q5}, [r1]!
++ vld1.8 {q6-q7}, [r1], r3
++ sub r1, #32
++ // load b
++ sub r1, #1
++ vld1.8 {q8-q9}, [r1]!
++ vld1.8 {q10-q11}, [r1]
++ sub r1, #31
++ edge_w64_body
++ // copy c to a
++ vmov.64 q0, q4
++ vmov.64 q1, q5
++ vmov.64 q2, q6
++ vmov.64 q3, q7
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_edge_eo0_w32_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ ldr r5, [r5]
++ vpush {d8-d15}
++ sub r1, #8 // load 8 extra bytes
++1: subs r4, #1
++ vld1.8 {q10-q11}, [r1]
++ add r1, #32
++ vld1.8 {q12}, [r1], r3 // only first 9 bytes are used
++ sub r1, #32
++ // a
++ vext.8 q0, q10, q11, #7
++ vext.8 q1, q11, q12, #7
++ // c
++ vext.8 q4, q10, q11, #8
++ vext.8 q5, q11, q12, #8
++ // b
++ vext.8 q8, q10, q11, #9
++ vext.8 q9, q11, q12, #9
++ edge_w32_body
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_edge_eo1_w32_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ ldr r5, [r5]
++ vpush {d8-d15}
++ // load a
++ sub r1, r3
++ vld1.8 {q0-q1}, [r1], r3
++ // load c
++ vld1.8 {q4-q5}, [r1], r3
++1: subs r4, #1
++ // load b
++ vld1.8 {q8-q9}, [r1], r3
++ edge_w32_body
++ // inputs for next loop iteration
++ // a
++ vmov.64 q0, q4
++ vmov.64 q1, q5
++ // c
++ vmov.64 q4, q8
++ vmov.64 q5, q9
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_edge_eo2_w32_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ ldr r5, [r5]
++ vpush {d8-d15}
++ // load a
++ sub r1, r3
++ sub r1, #8
++ vld1.8 {q10-q11}, [r1]
++ add r1, #32
++ vld1.8 {q12}, [r1], r3
++ sub r1, #32
++ vext.8 q0, q10, q11, #7
++ vext.8 q1, q11, q12, #7
++ // load c
++ vld1.8 {q10-q11}, [r1]
++ add r1, #32
++ vld1.8 {q12}, [r1], r3
++ sub r1, #32
++ vext.8 q4, q10, q11, #8
++ vext.8 q5, q11, q12, #8
++ vext.8 q2, q10, q11, #7
++1: subs r4, #1
++ // load b
++ vld1.8 {q10-q11}, [r1]
++ add r1, #32
++ vld1.8 {q12}, [r1], r3
++ sub r1, #32
++ vext.8 q8, q10, q11, #9
++ vext.8 q9, q11, q12, #9
++ vext.8 q14, q10, q11, #8
++ vext.8 q15, q11, q12, #8
++ vext.8 q3, q10, q11, #7
++ edge_w32_body
++ // inputs for next loop iteration
++ // a
++ vmov.8 q0, q2
++ vext.8 q1, q4, q5, #15
++ // c
++ vmov.8 q4, q14
++ vmov.8 q5, q15
++ vmov.8 q2, q3
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
++function ff_hevc_sao_edge_eo3_w32_neon_8, export=1
++ push {r4-r8}
++ ldr r4, [sp, #20] // height
++ ldr r5, [sp, #24] // sao_offset_val_table
++ ldr r6, =0x03
++ ldr r7, [r5]
++ add r5, #4
++ sub r1, r3
++ ldr r5, [r5]
++ sub r1, #8
++ vpush {d8-d15}
++ // load a
++ vld1.8 {q10-q11}, [r1]
++ add r1, #32
++ vld1.8 {q12}, [r1], r3
++ sub r1, #32
++ vext.8 q0, q10, q11, #9
++ vext.8 q1, q11, q12, #9
++ // load c
++ vld1.8 {q10-q11}, [r1]
++ add r1, #32
++ vld1.8 {q12}, [r1], r3
++ sub r1, #32
++ vext.8 q4, q10, q11, #8
++ vext.8 q5, q11, q12, #8
++ vext.8 q2, q12, q11, #8
++1: subs r4, #1
++ // load b
++ vld1.8 {q10-q11}, [r1]
++ add r1, #32
++ vld1.8 {q12}, [r1], r3
++ sub r1, #32
++ vext.8 q8, q10, q11, #7
++ vext.8 q9, q11, q12, #7
++ vext.8 q3, q12, q10, #7
++ edge_w32_body
++ // inputs for next loop iteration
++ // a
++ vext.8 q0, q4, q5, #1
++ vext.8 q1, q5, q2, #1
++ // c
++ vext.8 q4, q8, q9, #1
++ vext.8 q5, q9, q3, #1
++ vext.8 q2, q3, q1, #1
++ bne 1b
++ vpop {d8-d15}
++ pop {r4-r8}
++ bx lr
++endfunc
++
+--
+2.5.0
+
+
+From 1898d052a73370166d57e17cc7c52b7275887df3 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Fri, 19 Dec 2014 09:44:10 +0200
+Subject: [PATCH 4/9] Improved SAO band NEON opimizations made SAO buffer 16
+ byte aligned added alignment hints to loads and stores optimized register
+ usage in SAO band neon assembly
+
+---
+ libavcodec/arm/hevcdsp_sao_neon.S | 212 +++++++++++++++-----------------------
+ 1 file changed, 82 insertions(+), 130 deletions(-)
+
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index 4687012..ac21013 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -22,120 +22,84 @@
+ #include "neon.S"
+
+ function ff_hevc_sao_band_w8_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // offset_table
+- vpush {d8-d15}
+- vld1.8 {q0, q1}, [r5] // offset table
++ ldr r12, [sp, #4] // offset_table address
++ vld1.8 {q0, q1}, [r12] // offset table
++ ldr r12, [sp, #0] // height
+
+-1: subs r4, #1
+- vld1.8 {d24}, [r1], r3
++1: subs r12, #1
++ vld1.8 {d24}, [r1,:64], r3
+ vshr.u8 d16, d24, #3
+ vtbl.8 d16, {q0, q1}, d16
+- vmovl.s8 q2, d16
+ vmovl.u8 q6, d24
+- vadd.s16 q2, q6
++ vaddw.s8 q6, d16
+ vqmovun.s16 d4, q2
+- vst1.8 {d4}, [r0], r2
++ vst1.8 {d4}, [r0,:64], r2
+ bne 1b
+
+- vpop {d8-d15}
+- pop {r4-r8}
+ bx lr
+ endfunc
+
+ function ff_hevc_sao_band_w16_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // offset_table
+- vpush {d8-d15}
+- vld1.8 {q0, q1}, [r5] // offset table
+-
+-1: subs r4, #1
+- vld1.8 {q12}, [r1], r3
++ ldr r12, [sp, #4] // offset_table address
++ vld1.8 {q0, q1}, [r12] // offset table
++ ldr r12, [sp, #0] // height
+
++1: subs r12, #1
++ vld1.8 {q12}, [r1,:128], r3
+ vshr.u8 q8, q12, #3
+-
+ vtbl.8 d16, {q0, q1}, d16
+ vtbl.8 d17, {q0, q1}, d17
+-
+- vmovl.s8 q2, d16
+- vmovl.s8 q3, d17
+-
+- vmovl.u8 q6, d24
+- vmovl.u8 q7, d25
+-
+- vadd.s16 q2, q6
+- vadd.s16 q3, q7
+-
+- vqmovun.s16 d4, q2
+- vqmovun.s16 d5, q3
+-
+- vstm.8 r0, {q2}
+- add r0, r2
++ vmovl.u8 q10, d24
++ vmovl.u8 q11, d25
++ vaddw.s8 q10, d16
++ vaddw.s8 q11, d17
++ vqmovun.s16 d4, q10
++ vqmovun.s16 d5, q11
++ vst1.8 {q2}, [r0,:128], r2
+ bne 1b
+
+- vpop {d8-d15}
+- pop {r4-r8}
+ bx lr
+ endfunc
+
+ function ff_hevc_sao_band_w32_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // offset_table
+- vpush {d8-d15}
+- vld1.8 {q0, q1}, [r5] // offset table
+-
+-1: subs r4, #1
+- vld1.8 {q12-q13}, [r1], r3
+-
+- vshr.u8 q8, q12, #3
+- vshr.u8 q9, q13, #3
+-
+- vtbl.8 d16, {q0, q1}, d16
+- vtbl.8 d17, {q0, q1}, d17
+- vtbl.8 d18, {q0, q1}, d18
+- vtbl.8 d19, {q0, q1}, d19
+-
+- vmovl.s8 q2, d16
+- vmovl.s8 q3, d17 // q8 free
+- vmovl.s8 q4, d18
+- vmovl.s8 q5, d19 // q9 free
+-
+- vmovl.u8 q6, d24
+- vmovl.u8 q7, d25 // q12 free
+- vmovl.u8 q8, d26
+- vmovl.u8 q9, d27 // q13 free
+-
+- vadd.s16 q2, q6
+- vadd.s16 q3, q7
+- vadd.s16 q4, q8
+- vadd.s16 q5, q9
+-
+- vqmovun.s16 d4, q2
+- vqmovun.s16 d5, q3
+- vqmovun.s16 d6, q4 // q4 free
+- vqmovun.s16 d7, q5 // q5 free
+-
+- vst1.8 {q2-q3}, [r0], r2
+- bne 1b
+-
+- vpop {d8-d15}
+- pop {r4-r8}
+- bx lr
++ ldr r12, [sp, #4] // offset_table address
++ vld1.8 {q0, q1}, [r12] // offset table
++ ldr r12, [sp, #0] // height
++
++1: subs r12, #1
++ vld1.8 {q2-q3}, [r1,:128], r3
++ vshr.u8 q8, q2, #3
++ vshr.u8 q9, q3, #3
++ vtbl.8 d16, {q0, q1}, d16
++ vtbl.8 d17, {q0, q1}, d17
++ vtbl.8 d18, {q0, q1}, d18
++ vtbl.8 d19, {q0, q1}, d19
++ vmovl.u8 q12, d4
++ vmovl.u8 q13, d5
++ vmovl.u8 q14, d6
++ vmovl.u8 q15, d7
++ vaddw.s8 q12, d16
++ vaddw.s8 q13, d17
++ vaddw.s8 q14, d18
++ vaddw.s8 q15, d19
++ vqmovun.s16 d4, q12
++ vqmovun.s16 d5, q13
++ vqmovun.s16 d6, q14
++ vqmovun.s16 d7, q15
++ vst1.8 {q2-q3}, [r0,:128], r2
++ bne 1b
++
++ bx lr
+ endfunc
+
+ function ff_hevc_sao_band_w64_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // offset_table
+- vpush {d8-d15}
+- vld1.8 {q0, q1}, [r5] // offset table
++ ldr r12, [sp, #4] // offset_table address
++ vld1.8 {q0, q1}, [r12] // offset table
++ ldr r12, [sp, #0] // height
+
+-1: subs r4, #1
+- vld1.8 {q12-q13}, [r1]!
+- vld1.8 {q14-q15}, [r1], r3
++1: subs r12, #1
++ vld1.8 {q12-q13}, [r1,:128]!
++ vld1.8 {q14-q15}, [r1,:128], r3
+ sub r1, #32
+
+ vshr.u8 q8, q12, #3
+@@ -152,53 +116,41 @@ function ff_hevc_sao_band_w64_neon_8, export=1
+ vtbl.8 d22, {q0, q1}, d22
+ vtbl.8 d23, {q0, q1}, d23
+
+- vmovl.s8 q2, d16
+- vmovl.s8 q3, d17 // q8 free
+- vmovl.s8 q4, d18
+- vmovl.s8 q5, d19 // q9 free
++ vmovl.u8 q2, d24
++ vmovl.u8 q3, d25
++ vmovl.u8 q12, d26
++ vmovl.u8 q13, d27
+
+- vmovl.u8 q6, d24
+- vmovl.u8 q7, d25 // q12 free
+- vmovl.u8 q8, d26
+- vmovl.u8 q9, d27 // q13 free
+-
+- vadd.s16 q2, q6
+- vadd.s16 q3, q7
+- vadd.s16 q4, q8
+- vadd.s16 q5, q9
++ vaddw.s8 q2, d16
++ vaddw.s8 q3, d17
++ vaddw.s8 q12, d18
++ vaddw.s8 q13, d19
+
+ vqmovun.s16 d4, q2
+ vqmovun.s16 d5, q3
+- vqmovun.s16 d6, q4 // q4 free
+- vqmovun.s16 d7, q5 // q5 free
+-
+- // free q4 -q9, q12 - q13
+- vmovl.s8 q4, d20
+- vmovl.s8 q5, d21 // q10 free
+- vmovl.s8 q6, d22
+- vmovl.s8 q7, d23 // q11 free
+-
+- vmovl.u8 q8, d28
+- vmovl.u8 q9, d29 // q14 free
+- vmovl.u8 q10, d30
+- vmovl.u8 q11, d31 // q15 free
+-
+- vadd.s16 q4, q8
+- vadd.s16 q5, q9
+- vadd.s16 q6, q10
+- vadd.s16 q7, q11
+-
+- vqmovun.s16 d8, q4
+- vqmovun.s16 d9, q5
+- vqmovun.s16 d10, q6
+- vqmovun.s16 d11, q7
+-
+- vstm.8 r0, {q2-q5}
+- add r0, r2
++ vqmovun.s16 d6, q12
++ vqmovun.s16 d7, q13
++
++ vmovl.u8 q12, d28
++ vmovl.u8 q13, d29
++ vmovl.u8 q14, d30
++ vmovl.u8 q15, d31
++
++ vaddw.s8 q12, d20
++ vaddw.s8 q13, d21
++ vaddw.s8 q14, d22
++ vaddw.s8 q15, d23
++
++ vqmovun.s16 d8, q12
++ vqmovun.s16 d9, q13
++ vqmovun.s16 d10, q14
++ vqmovun.s16 d11, q15
++
++ vst1.8 {q2-q3}, [r0,:128]!
++ vst1.8 {q4-q5}, [r0,:128], r2
++ sub r0, #32
+ bne 1b
+
+- vpop {d8-d15}
+- pop {r4-r8}
+ bx lr
+ endfunc
+
+--
+2.5.0
+
+
+From 26bd536800db2f50ff6a021e1fda0d0394d1ea01 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Mon, 29 Dec 2014 15:00:49 +0200
+Subject: [PATCH 5/9] better code reuse in NEON SAO band
+
+---
+ libavcodec/arm/hevcdsp_init_neon.c | 16 ++--
+ libavcodec/arm/hevcdsp_sao_neon.S | 155 +++++++++++++------------------------
+ 2 files changed, 61 insertions(+), 110 deletions(-)
+
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index c32940e..6379810 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -45,10 +45,10 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs,
+ void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs,
+ ptrdiff_t stride);
+
+-void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
+-void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
+-void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
+-void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
++void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
++void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
++void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
++void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
+
+ void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
+ void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
+@@ -185,16 +185,16 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
+
+ switch(width){
+ case 8:
+- ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
+ break;
+ case 16:
+- ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
+ break;
+ case 32:
+- ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
+ break;
+ case 64:
+- ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
++ ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
+ break;
+ default:
+ for (y = 0; y < height; y++) {
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index ac21013..8852550 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -21,53 +21,13 @@
+ #include "libavutil/arm/asm.S"
+ #include "neon.S"
+
+-function ff_hevc_sao_band_w8_neon_8, export=1
+- ldr r12, [sp, #4] // offset_table address
++.macro init_sao_band
++ ldr r12, [sp, #0] // offset_table address
+ vld1.8 {q0, q1}, [r12] // offset table
+- ldr r12, [sp, #0] // height
+-
+-1: subs r12, #1
+- vld1.8 {d24}, [r1,:64], r3
+- vshr.u8 d16, d24, #3
+- vtbl.8 d16, {q0, q1}, d16
+- vmovl.u8 q6, d24
+- vaddw.s8 q6, d16
+- vqmovun.s16 d4, q2
+- vst1.8 {d4}, [r0,:64], r2
+- bne 1b
+-
+- bx lr
+-endfunc
+-
+-function ff_hevc_sao_band_w16_neon_8, export=1
+- ldr r12, [sp, #4] // offset_table address
+- vld1.8 {q0, q1}, [r12] // offset table
+- ldr r12, [sp, #0] // height
+-
+-1: subs r12, #1
+- vld1.8 {q12}, [r1,:128], r3
+- vshr.u8 q8, q12, #3
+- vtbl.8 d16, {q0, q1}, d16
+- vtbl.8 d17, {q0, q1}, d17
+- vmovl.u8 q10, d24
+- vmovl.u8 q11, d25
+- vaddw.s8 q10, d16
+- vaddw.s8 q11, d17
+- vqmovun.s16 d4, q10
+- vqmovun.s16 d5, q11
+- vst1.8 {q2}, [r0,:128], r2
+- bne 1b
+-
+- bx lr
+-endfunc
+-
+-function ff_hevc_sao_band_w32_neon_8, export=1
+- ldr r12, [sp, #4] // offset_table address
+- vld1.8 {q0, q1}, [r12] // offset table
+- ldr r12, [sp, #0] // height
++ ldr r12, [sp, #4] // height
++.endm
+
+-1: subs r12, #1
+- vld1.8 {q2-q3}, [r1,:128], r3
++.macro sao_band_32
+ vshr.u8 q8, q2, #3
+ vshr.u8 q9, q3, #3
+ vtbl.8 d16, {q0, q1}, d16
+@@ -86,6 +46,43 @@ function ff_hevc_sao_band_w32_neon_8, export=1
+ vqmovun.s16 d5, q13
+ vqmovun.s16 d6, q14
+ vqmovun.s16 d7, q15
++.endm
++
++function ff_hevc_sao_band_w8_neon_8, export=1
++ init_sao_band
++1: subs r12, #4
++ vld1.8 {d4}, [r1,:64], r3
++ vld1.8 {d5}, [r1,:64], r3
++ vld1.8 {d6}, [r1,:64], r3
++ vld1.8 {d7}, [r1,:64], r3
++ sao_band_32
++ vst1.8 {d4}, [r0,:64], r2
++ vst1.8 {d5}, [r0,:64], r2
++ vst1.8 {d6}, [r0,:64], r2
++ vst1.8 {d7}, [r0,:64], r2
++ bne 1b
++
++ bx lr
++endfunc
++
++function ff_hevc_sao_band_w16_neon_8, export=1
++ init_sao_band
++1: subs r12, #2
++ vld1.8 {q2}, [r1,:128], r3
++ vld1.8 {q3}, [r1,:128], r3
++ sao_band_32
++ vst1.8 {q2}, [r0,:128], r2
++ vst1.8 {q3}, [r0,:128], r2
++ bne 1b
++
++ bx lr
++endfunc
++
++function ff_hevc_sao_band_w32_neon_8, export=1
++ init_sao_band
++1: subs r12, #1
++ vld1.8 {q2-q3}, [r1,:128], r3
++ sao_band_32
+ vst1.8 {q2-q3}, [r0,:128], r2
+ bne 1b
+
+@@ -93,63 +90,17 @@ function ff_hevc_sao_band_w32_neon_8, export=1
+ endfunc
+
+ function ff_hevc_sao_band_w64_neon_8, export=1
+- ldr r12, [sp, #4] // offset_table address
+- vld1.8 {q0, q1}, [r12] // offset table
+- ldr r12, [sp, #0] // height
+-
+-1: subs r12, #1
+- vld1.8 {q12-q13}, [r1,:128]!
+- vld1.8 {q14-q15}, [r1,:128], r3
+- sub r1, #32
+-
+- vshr.u8 q8, q12, #3
+- vshr.u8 q9, q13, #3
+- vshr.u8 q10, q14, #3
+- vshr.u8 q11, q15, #3
+-
+- vtbl.8 d16, {q0, q1}, d16
+- vtbl.8 d17, {q0, q1}, d17
+- vtbl.8 d18, {q0, q1}, d18
+- vtbl.8 d19, {q0, q1}, d19
+- vtbl.8 d20, {q0, q1}, d20
+- vtbl.8 d21, {q0, q1}, d21
+- vtbl.8 d22, {q0, q1}, d22
+- vtbl.8 d23, {q0, q1}, d23
+-
+- vmovl.u8 q2, d24
+- vmovl.u8 q3, d25
+- vmovl.u8 q12, d26
+- vmovl.u8 q13, d27
+-
+- vaddw.s8 q2, d16
+- vaddw.s8 q3, d17
+- vaddw.s8 q12, d18
+- vaddw.s8 q13, d19
+-
+- vqmovun.s16 d4, q2
+- vqmovun.s16 d5, q3
+- vqmovun.s16 d6, q12
+- vqmovun.s16 d7, q13
+-
+- vmovl.u8 q12, d28
+- vmovl.u8 q13, d29
+- vmovl.u8 q14, d30
+- vmovl.u8 q15, d31
+-
+- vaddw.s8 q12, d20
+- vaddw.s8 q13, d21
+- vaddw.s8 q14, d22
+- vaddw.s8 q15, d23
+-
+- vqmovun.s16 d8, q12
+- vqmovun.s16 d9, q13
+- vqmovun.s16 d10, q14
+- vqmovun.s16 d11, q15
+-
+- vst1.8 {q2-q3}, [r0,:128]!
+- vst1.8 {q4-q5}, [r0,:128], r2
+- sub r0, #32
+- bne 1b
++ init_sao_band
++1: subs r12, #1
++ vld1.8 {q2-q3}, [r1,:128]!
++ sao_band_32
++ vst1.8 {q2-q3}, [r0,:128]!
++ vld1.8 {q2-q3}, [r1,:128], r3
++ sub r1, #32
++ sao_band_32
++ vst1.8 {q2-q3}, [r0,:128], r2
++ sub r0, #32
++ bne 1b
+
+ bx lr
+ endfunc
+--
+2.5.0
+
+
+From f93646a97bc885b81759e774d04be3781916a3e7 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Wed, 7 Jan 2015 15:27:38 +0200
+Subject: [PATCH 6/9] More SAO NEON optimizations Now uses only 8 bit integers
+ for SAO calculations
+
+---
+ libavcodec/arm/hevcdsp_init_neon.c | 7 +-
+ libavcodec/arm/hevcdsp_sao_neon.S | 664 +++++++++++++++----------------------
+ 2 files changed, 272 insertions(+), 399 deletions(-)
+
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index 6379810..8d6e863 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -225,7 +225,7 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
+ int x, y;
+
+ for (x = 0; x < 5; x++) {
+- sao_offset_val[x] = _sao_offset_val[x];
++ sao_offset_val[x] = _sao_offset_val[edge_idx[x]];
+ }
+
+ stride_src /= sizeof(pixel);
+@@ -271,8 +271,9 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
+ for (x = 0; x < width; x++) {
+ int diff0 = CMP(src[x], src[x + a_stride]);
+ int diff1 = CMP(src[x], src[x + b_stride]);
+- int offset_val = edge_idx[2 + diff0 + diff1];
+- dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);
++ int idx = diff0 + diff1;
++ if (idx)
++ dst[x] = av_clip_pixel(src[x] + sao_offset_val[idx+2]);
+ }
+ src += stride_src;
+ dst += stride_dst;
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index 8852550..5fc482b 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (c) 2014 Seppo Tomperi
++ * Copyright (c) 2014 - 2015 Seppo Tomperi
+ *
+ * This file is part of FFmpeg.
+ *
+@@ -23,6 +23,7 @@
+
+ .macro init_sao_band
+ ldr r12, [sp, #0] // offset_table address
++ pld [r1]
+ vld1.8 {q0, q1}, [r12] // offset table
+ ldr r12, [sp, #4] // height
+ .endm
+@@ -30,36 +31,31 @@
+ .macro sao_band_32
+ vshr.u8 q8, q2, #3
+ vshr.u8 q9, q3, #3
++ vmov.u8 q14, #128
+ vtbl.8 d16, {q0, q1}, d16
+ vtbl.8 d17, {q0, q1}, d17
+ vtbl.8 d18, {q0, q1}, d18
+ vtbl.8 d19, {q0, q1}, d19
+- vmovl.u8 q12, d4
+- vmovl.u8 q13, d5
+- vmovl.u8 q14, d6
+- vmovl.u8 q15, d7
+- vaddw.s8 q12, d16
+- vaddw.s8 q13, d17
+- vaddw.s8 q14, d18
+- vaddw.s8 q15, d19
+- vqmovun.s16 d4, q12
+- vqmovun.s16 d5, q13
+- vqmovun.s16 d6, q14
+- vqmovun.s16 d7, q15
++ vadd.s8 q2, q14
++ vadd.s8 q3, q14
++ vqadd.s8 q2, q8
++ vqadd.s8 q3, q9
++ vsub.s8 q2, q14
++ vsub.s8 q3, q14
+ .endm
+
+ function ff_hevc_sao_band_w8_neon_8, export=1
+ init_sao_band
+ 1: subs r12, #4
+- vld1.8 {d4}, [r1,:64], r3
+- vld1.8 {d5}, [r1,:64], r3
+- vld1.8 {d6}, [r1,:64], r3
+- vld1.8 {d7}, [r1,:64], r3
++ vld1.8 {d4}, [r1, :64], r3
++ vld1.8 {d5}, [r1, :64], r3
++ vld1.8 {d6}, [r1, :64], r3
++ vld1.8 {d7}, [r1, :64], r3
+ sao_band_32
+- vst1.8 {d4}, [r0,:64], r2
+- vst1.8 {d5}, [r0,:64], r2
+- vst1.8 {d6}, [r0,:64], r2
+- vst1.8 {d7}, [r0,:64], r2
++ vst1.8 {d4}, [r0, :64], r2
++ vst1.8 {d5}, [r0, :64], r2
++ vst1.8 {d6}, [r0, :64], r2
++ vst1.8 {d7}, [r0, :64], r2
+ bne 1b
+
+ bx lr
+@@ -68,11 +64,11 @@ endfunc
+ function ff_hevc_sao_band_w16_neon_8, export=1
+ init_sao_band
+ 1: subs r12, #2
+- vld1.8 {q2}, [r1,:128], r3
+- vld1.8 {q3}, [r1,:128], r3
++ vld1.8 {q2}, [r1, :128], r3
++ vld1.8 {q3}, [r1, :128], r3
+ sao_band_32
+- vst1.8 {q2}, [r0,:128], r2
+- vst1.8 {q3}, [r0,:128], r2
++ vst1.8 {q2}, [r0, :128], r2
++ vst1.8 {q3}, [r0, :128], r2
+ bne 1b
+
+ bx lr
+@@ -81,9 +77,9 @@ endfunc
+ function ff_hevc_sao_band_w32_neon_8, export=1
+ init_sao_band
+ 1: subs r12, #1
+- vld1.8 {q2-q3}, [r1,:128], r3
++ vld1.8 {q2-q3}, [r1, :128], r3
+ sao_band_32
+- vst1.8 {q2-q3}, [r0,:128], r2
++ vst1.8 {q2-q3}, [r0, :128], r2
+ bne 1b
+
+ bx lr
+@@ -92,263 +88,153 @@ endfunc
+ function ff_hevc_sao_band_w64_neon_8, export=1
+ init_sao_band
+ 1: subs r12, #1
+- vld1.8 {q2-q3}, [r1,:128]!
++ pld [r1, r3]
++ vld1.8 {q2-q3}, [r1, :128]!
+ sao_band_32
+- vst1.8 {q2-q3}, [r0,:128]!
+- vld1.8 {q2-q3}, [r1,:128], r3
++ vst1.8 {q2-q3}, [r0, :128]!
++ vld1.8 {q2-q3}, [r1, :128], r3
+ sub r1, #32
+ sao_band_32
+- vst1.8 {q2-q3}, [r0,:128], r2
++ vst1.8 {q2-q3}, [r0, :128], r2
+ sub r0, #32
+ bne 1b
+
+ bx lr
+ endfunc
+-
++// input
++// a in q0 - q3
++// c in q4 - q7
++// b in q8 - q11
++// offset table in r7 and r5
++// output in q0 - q3
++// clobbers q12 - q15
+ .macro edge_w64_body
+- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
+- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
+- vcgt.u8 q13, q5, q1
+- vcgt.u8 q1, q1, q5
+- vcgt.u8 q14, q6, q2
+- vcgt.u8 q2, q2, q6
+- vcgt.u8 q15, q7, q3
+- vcgt.u8 q3, q3, q7
+-
+- vsub.s8 q12, q0, q12 // diff0
+- vsub.s8 q13, q1, q13
+- vsub.s8 q14, q2, q14
+- vsub.s8 q15, q3, q15
+-
++ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
++ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
++ vcgt.u8 q13, q5, q1
++ vcgt.u8 q1, q1, q5
++ vsub.s8 q12, q0, q12 // diff0
+ vcgt.u8 q0, q4, q8 // c > b
+- vcgt.u8 q8, q8, q4 // b > c
++ vsub.s8 q13, q1, q13
++
++ vcgt.u8 q14, q8, q4 // b > c
+ vcgt.u8 q1, q5, q9
+- vcgt.u8 q9, q9, q5
+- vcgt.u8 q2, q6, q10
+- vcgt.u8 q10, q10, q6
+- vcgt.u8 q3, q7, q11
+- vcgt.u8 q11, q11, q7
++ vcgt.u8 q15, q9, q5
++ vsub.s8 q0, q14, q0 // diff1
+
+- vsub.s8 q0, q8, q0 // diff1
+- vsub.s8 q1, q9, q1
+- vsub.s8 q2, q10, q2
+- vsub.s8 q3, q11, q3
++ vsub.s8 q1, q15, q1
+
+- vadd.s8 q0, q12 //diff0 + diff1
+- vadd.s8 q1, q13
+- vadd.s8 q2, q14
+- vadd.s8 q3, q15
+-
+- vdup.s8 q9, r6 // 3 to all elements
+- sub r6, #1
+-
+- vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
+- vclt.s8 q13, q1, #0
+- vclt.s8 q14, q2, #0
+- vclt.s8 q15, q3, #0
+-
+- vadd.s8 q8, q0, q9 // diff0 + diff1 + 3
+- vadd.s8 q10, q1, q9
+- vand.8 q12, q8, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
+- vand.8 q13, q10, q13
+- vadd.s8 q8, q2, q9
+- vadd.s8 q10, q3, q9
+- vand.8 q14, q8, q14
+- vand.8 q15, q10, q15
+-
+- vdup.s8 q9, r6 // 2 to all elements
+- add r6, #1
+-
+- vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
+- vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
+- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
+- vcgt.s8 q10, q1, #0
+- vadd.s8 q0, q11, q12 // offset_idx
+-
+- vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
+- vcgt.s8 q12, q2, #0
+- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
+- vadd.s8 q8, q2, q9 // diff0 + diff1 + 2
+- vadd.s8 q1, q11, q13
+-
+- vand.8 q11, q8, q12 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
+- vcgt.s8 q10, q3, #0
+- vadd.s8 q2, q11, q14
+-
+- vadd.s8 q8, q3, q9 // diff0 + diff1 + 2
+- vmov.32 d18[0], r7 // load offset table from general registers
+- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
+- vmov.32 d18[1], r5 // load rest of offset table
+- vadd.s8 q3, q11, q15
+-
+- vtbl.8 d0, {d18}, d0
+- vtbl.8 d1, {d18}, d1
+- vtbl.8 d2, {d18}, d2
+- vtbl.8 d3, {d18}, d3
+- vtbl.8 d4, {d18}, d4
+- vtbl.8 d5, {d18}, d5
+- vtbl.8 d6, {d18}, d6
+- vtbl.8 d7, {d18}, d7
+-
+- vmovl.u8 q8, d8
+- vmovl.u8 q9, d9
+- vmovl.u8 q10, d10
+- vmovl.u8 q11, d11
+- vmovl.u8 q12, d12
+- vmovl.u8 q13, d13
+- vmovl.u8 q14, d14
+- vmovl.u8 q15, d15
+-
+- vaddw.s8 q8, d0
+- vaddw.s8 q9, d1
+- vaddw.s8 q10, d2
+- vaddw.s8 q11, d3
+- vaddw.s8 q12, d4
+- vaddw.s8 q13, d5
+- vaddw.s8 q14, d6
+- vaddw.s8 q15, d7
+-
+- vqmovun.s16 d0, q8
+- vqmovun.s16 d1, q9
+- vqmovun.s16 d2, q10
+- vqmovun.s16 d3, q11
+- vqmovun.s16 d4, q12
+- vqmovun.s16 d5, q13
+- vqmovun.s16 d6, q14
+- vqmovun.s16 d7, q15
+-
+- vstm r0, {q0-q3}
+- add r0, r2
+-.endm
++ vadd.s8 q0, q12 //diff0 + diff1
++ vadd.s8 q1, q13
+
+-.macro edge_w32_body
+- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
+- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
+- vcgt.u8 q13, q5, q1
+- vcgt.u8 q1, q1, q5
++ vcgt.u8 q14, q6, q2
++ vcgt.u8 q2, q2, q6
++ vcgt.u8 q15, q7, q3
++ vcgt.u8 q3, q3, q7
+
+- vsub.s8 q12, q0, q12 // diff0
+- vcgt.u8 q0, q4, q8 // c > b
+- vsub.s8 q13, q1, q13 // diff0 part 2
++ vsub.s8 q14, q2, q14
++ vcgt.u8 q2, q6, q10
++ vsub.s8 q15, q3, q15
+
+- vcgt.u8 q6, q8, q4 // b > c
+- vcgt.u8 q1, q5, q9
+- vcgt.u8 q7, q9, q5
++ vcgt.u8 q12, q10, q6
++ vcgt.u8 q3, q7, q11
++ vcgt.u8 q13, q11, q7
++ vsub.s8 q2, q12, q2
++ vsub.s8 q3, q13, q3
+
+- vsub.s8 q0, q6, q0 // diff1
+- vsub.s8 q1, q7, q1 // diff1 part 2
+- vadd.s8 q0, q12 //diff0 + diff1
++ vmov.s8 q13, #2 // 2 to all elements
+
+- vdup.s8 q7, r6 // 3 to all elements
+- sub r6, #1
+- vadd.s8 q1, q13
++ vadd.s8 q2, q14
++ vadd.s8 q3, q15
++
++ vmov.32 d24[0], r4 // load offset table from general registers
++ vmov.32 d24[1], r5 // load rest of offset table
+
+- vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
+- vclt.s8 q13, q1, #0
+-
+- vadd.s8 q6, q0, q7 // diff0 + diff1 + 3
+- vadd.s8 q10, q1, q7
+- vdup.s8 q7, r6 // 2 to all elements
+- add r6, #1
+- vand.8 q12, q6, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
+- vand.8 q13, q10, q13
+-
+-
+- vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
+- vadd.s8 q6, q0, q7 // diff0 + diff1 + 2
+- vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
+- vcgt.s8 q10, q1, #0
+- vadd.s8 q0, q11, q12 // offset_idx
+-
+- vadd.s8 q6, q1, q7 // diff0 + diff1 + 2
+- vmov.32 d14[0], r7 // load offset table from general registers
+- vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
+- vmov.32 d14[1], r5 // load rest of offset table
+- vadd.s8 q1, q11, q13
+-
+- vtbl.8 d0, {d14}, d0
+- vtbl.8 d1, {d14}, d1
+- vtbl.8 d2, {d14}, d2
+- vtbl.8 d3, {d14}, d3
+-
+- vmovl.u8 q6, d8
+- vmovl.u8 q7, d9
+- vmovl.u8 q10, d10
+- vmovl.u8 q11, d11
+-
+- vaddw.s8 q6, d0
+- vaddw.s8 q7, d1
+- vaddw.s8 q10, d2
+- vaddw.s8 q11, d3
+-
+- vqmovun.s16 d0, q6
+- vqmovun.s16 d1, q7
+- vqmovun.s16 d2, q10
+- vqmovun.s16 d3, q11
+-
+- vstm r0, {q0-q1}
+- add r0, r2
++ vadd.s8 q0, q13
++ vadd.s8 q1, q13
++ vadd.s8 q2, q13
++ vadd.s8 q3, q13
++
++ vmov.u8 q15, #128 // s8 #-128
++ vtbl.8 d0, {d24}, d0
++ vtbl.8 d1, {d24}, d1
++ vtbl.8 d2, {d24}, d2
++ vtbl.8 d3, {d24}, d3
++ vtbl.8 d4, {d24}, d4
++ vtbl.8 d5, {d24}, d5
++ vtbl.8 d6, {d24}, d6
++ vtbl.8 d7, {d24}, d7
++
++ vadd.s8 q12, q4, q15
++ vadd.s8 q13, q5, q15
++ vadd.s8 q14, q6, q15
++ vadd.s8 q15, q7, q15
++ vqadd.s8 q12, q0
++ vqadd.s8 q15, q3
++ vmov.u8 q3, #128 // s8 #-128
++ vqadd.s8 q13, q1
++ vqadd.s8 q14, q2
++ vsub.s8 q0, q12, q3
++ vsub.s8 q1, q13, q3
++ vsub.s8 q2, q14, q3
++ vsub.s8 q3, q15, q3
++ vst1.8 {q0-q1}, [r0, :128]!
++ vst1.8 {q2-q3}, [r0, :128], r2
++ sub r0, #32
+ .endm
+
+-function ff_hevc_sao_edge_eo0_w64_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
++.macro init_edge_64
++ push {r4-r5}
++ ldr r12, [sp, #8] // height
++ ldr r5, [sp, #12] // sao_offset_val_table
++ ldr r4, [r5]
+ add r5, #4
+ ldr r5, [r5]
++.endm
++
++function ff_hevc_sao_edge_eo0_w64_neon_8, export=1
++ init_edge_64
+ vpush {d8-d15}
+ sub r1, #8
+-1: subs r4, #1
+- vld1.64 {q10-q11}, [r1]!
+- vld1.64 {q12-q13}, [r1]!
+- vld1.64 {q14}, [r1], r3
+- sub r1, #64
++1: subs r12, #1
++ vld1.64 {d7}, [r1, :64]!
++ vld1.64 {q4-q5}, [r1, :128]! // load c
++ vld1.64 {q6-q7}, [r1, :128]!
++ vld1.64 {d24}, [r1, :64], r3
++ sub r1, #72
+ // load a
+- vext.8 q0, q10, q11, #7
+- vext.8 q1, q11, q12, #7
+- vext.8 q2, q12, q13, #7
+- vext.8 q3, q13, q14, #7
+- // load c
+- vext.8 q4, q10, q11, #8
+- vext.8 q5, q11, q12, #8
+- vext.8 q6, q12, q13, #8
+- vext.8 q7, q13, q14, #8
++ vext.8 q0, q3, q4, #15
++ vext.8 q1, q4, q5, #15
++ vext.8 q2, q5, q6, #15
++ vext.8 q3, q6, q7, #15
+ // load b
+- vext.8 q8, q10, q11, #9
+- vext.8 q9, q11, q12, #9
+- vext.8 q10, q12, q13, #9
+- vext.8 q11, q13, q14, #9
++ vext.8 q8, q4, q5, #1
++ vext.8 q9, q5, q6, #1
++ vext.8 q10, q6, q7, #1
++ vext.8 q11, q7, q12, #1
+ edge_w64_body
+ bne 1b
+ vpop {d8-d15}
+- pop {r4-r8}
++ pop {r4-r5}
+ bx lr
+ endfunc
+
+ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
+- add r5, #4
+- ldr r5, [r5]
++ init_edge_64
+ vpush {d8-d15}
+ sub r1, r3
+ // load a
+- vld1.8 {q0-q1}, [r1]!
+- vld1.8 {q2-q3}, [r1], r3
++ vld1.8 {q0-q1}, [r1, :128]!
++ vld1.8 {q2-q3}, [r1, :128], r3
+ sub r1, #32
+-1: subs r4, #1
+ // load c
+- vld1.8 {q4-q5}, [r1]!
+- vld1.8 {q6-q7}, [r1], r3
++ vld1.8 {q4-q5}, [r1, :128]!
++ vld1.8 {q6-q7}, [r1, :128], r3
+ sub r1, #32
++1: subs r12, #1
+ // load b
+- vld1.8 {q8-q9}, [r1]!
+- vld1.8 {q10-q11}, [r1]
++ vld1.8 {q8-q9}, [r1, :128]!
++ vld1.8 {q10-q11}, [r1, :128], r3
+ sub r1, #32
+ edge_w64_body
+ // copy c to a
+@@ -356,20 +242,19 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
+ vmov.64 q1, q5
+ vmov.64 q2, q6
+ vmov.64 q3, q7
++ // copy b to c
++ vmov.64 q4, q8
++ vmov.64 q5, q9
++ vmov.64 q6, q10
++ vmov.64 q7, q11
+ bne 1b
+ vpop {d8-d15}
+- pop {r4-r8}
++ pop {r4-r5}
+ bx lr
+ endfunc
+
+ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
+- add r5, #4
+- ldr r5, [r5]
++ init_edge_64
+ vpush {d8-d15}
+ 1: sub r1, r3
+ // load a
+@@ -379,10 +264,10 @@ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
+ vld1.8 {q0-q1}, [r1]!
+ vld1.8 {q2-q3}, [r1], r3
+ sub r1, #31
+- subs r4, #1
++ subs r12, #1
+ // load c
+- vld1.8 {q4-q5}, [r1]!
+- vld1.8 {q6-q7}, [r1], r3
++ vld1.8 {q4-q5}, [r1, :128]!
++ vld1.8 {q6-q7}, [r1, :128], r3
+ sub r1, #32
+ // load b
+ add r1, #1
+@@ -390,25 +275,14 @@ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
+ vld1.8 {q10-q11}, [r1]
+ sub r1, #33
+ edge_w64_body
+- // copy c to a
+- vmov.64 q0, q4
+- vmov.64 q1, q5
+- vmov.64 q2, q6
+- vmov.64 q3, q7
+ bne 1b
+ vpop {d8-d15}
+- pop {r4-r8}
++ pop {r4-r5}
+ bx lr
+ endfunc
+
+ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
+- add r5, #4
+- ldr r5, [r5]
++ init_edge_64
+ vpush {d8-d15}
+ 1: sub r1, r3
+ // load a
+@@ -418,10 +292,10 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
+ vld1.8 {q0-q1}, [r1]!
+ vld1.8 {q2-q3}, [r1], r3
+ sub r1, #33
+- subs r4, #1
++ subs r12, #1
+ // load c
+- vld1.8 {q4-q5}, [r1]!
+- vld1.8 {q6-q7}, [r1], r3
++ vld1.8 {q4-q5}, [r1, :128]!
++ vld1.8 {q6-q7}, [r1, :128], r3
+ sub r1, #32
+ // load b
+ sub r1, #1
+@@ -429,178 +303,176 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
+ vld1.8 {q10-q11}, [r1]
+ sub r1, #31
+ edge_w64_body
+- // copy c to a
+- vmov.64 q0, q4
+- vmov.64 q1, q5
+- vmov.64 q2, q6
+- vmov.64 q3, q7
+ bne 1b
+ vpop {d8-d15}
+- pop {r4-r8}
++ pop {r4-r5}
+ bx lr
+ endfunc
+
++// inputs:
++// a in q0, q1
++// c in q2, q3
++// b in q8, q9
++// offset table in d31
++// clobbered registers q0, q1, q10, q11, q12, q13
++// output q0, q1
++.macro edge_w32_body
++ vcgt.u8 q12, q2, q0 // c > a -> -1 , otherwise 0
++ vcgt.u8 q0, q0, q2 // a > c -> -1 , otherwise 0
++ vcgt.u8 q13, q3, q1
++ vcgt.u8 q1, q1, q3
++
++ vsub.s8 q12, q0, q12 // diff0
++ vcgt.u8 q0, q2, q8 // c > b
++ vsub.s8 q13, q1, q13 // diff0 part 2
++
++ vcgt.u8 q10, q8, q2 // b > c
++ vcgt.u8 q1, q3, q9
++ vcgt.u8 q11, q9, q3
++
++ vsub.s8 q0, q10, q0 // diff1
++
++ vmov.s8 q10, #2 // 2 to all elements
++ vsub.s8 q1, q11, q1 // diff1 part 2
++ vadd.s8 q0, q12 //diff0 + diff1
++ vadd.s8 q1, q13
++
++ vadd.s8 q0, q10
++ vadd.s8 q1, q10
++
++ vmov.u8 q10, #128
++ vtbl.8 d0, {d31}, d0
++ vtbl.8 d1, {d31}, d1
++ vtbl.8 d2, {d31}, d2
++ vtbl.8 d3, {d31}, d3
++
++ vadd.s8 q11, q2, q10
++ vadd.s8 q12, q3, q10
++ vqadd.s8 q11, q0
++ vqadd.s8 q12, q1
++ vsub.s8 q0, q11, q10
++ vsub.s8 q1, q12, q10
++ vst1.8 {q0-q1}, [r0, :128], r2
++.endm
++
++.macro init_edge_32
++ ldr r12, [sp, #4] // sao_offset_val_table
++ vld1.32 {d31}, [r12]
++ ldr r12, [sp] // height
++.endm
++
+ function ff_hevc_sao_edge_eo0_w32_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
+- add r5, #4
+- ldr r5, [r5]
+- vpush {d8-d15}
+- sub r1, #8 // load 8 extra bytes
+-1: subs r4, #1
+- vld1.8 {q10-q11}, [r1]
+- add r1, #32
+- vld1.8 {q12}, [r1], r3 // only first 9 bytes are used
+- sub r1, #32
++ init_edge_32
++ sub r1, #4 // load 4 extra bytes
++1: subs r12, #1
++ vld1.32 d3[1], [r1]!
++ vld1.8 {q2-q3}, [r1, :128]! // c
++ vld1.32 d20[0], [r1], r3
++ sub r1, #36
+ // a
+- vext.8 q0, q10, q11, #7
+- vext.8 q1, q11, q12, #7
+- // c
+- vext.8 q4, q10, q11, #8
+- vext.8 q5, q11, q12, #8
++ vext.8 q0, q1, q2, #15
++ vext.8 q1, q2, q3, #15
+ // b
+- vext.8 q8, q10, q11, #9
+- vext.8 q9, q11, q12, #9
++ vext.8 q8, q2, q3, #1
++ vext.8 q9, q3, q10, #1
+ edge_w32_body
+- bne 1b
+- vpop {d8-d15}
+- pop {r4-r8}
+- bx lr
++ bne 1b
++ bx lr
+ endfunc
+
+ function ff_hevc_sao_edge_eo1_w32_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
+- add r5, #4
+- ldr r5, [r5]
+- vpush {d8-d15}
++ init_edge_32
+ // load a
+ sub r1, r3
+- vld1.8 {q0-q1}, [r1], r3
++ vld1.8 {q0-q1}, [r1, :128], r3
+ // load c
+- vld1.8 {q4-q5}, [r1], r3
+-1: subs r4, #1
++ vld1.8 {q2-q3}, [r1, :128], r3
++1: subs r12, #1
+ // load b
+- vld1.8 {q8-q9}, [r1], r3
++ vld1.8 {q8-q9}, [r1, :128], r3
+ edge_w32_body
+ // inputs for next loop iteration
+ // a
+- vmov.64 q0, q4
+- vmov.64 q1, q5
++ vmov.64 q0, q2
++ vmov.64 q1, q3
+ // c
+- vmov.64 q4, q8
+- vmov.64 q5, q9
+- bne 1b
+- vpop {d8-d15}
+- pop {r4-r8}
+- bx lr
++ vmov.64 q2, q8
++ vmov.64 q3, q9
++ bne 1b
++ bx lr
+ endfunc
+
+ function ff_hevc_sao_edge_eo2_w32_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
+- add r5, #4
+- ldr r5, [r5]
+- vpush {d8-d15}
++ init_edge_32
++ vpush {d8-d15}
+ // load a
+ sub r1, r3
+- sub r1, #8
+- vld1.8 {q10-q11}, [r1]
+- add r1, #32
+- vld1.8 {q12}, [r1], r3
+- sub r1, #32
++ sub r1, #8
++ vld1.8 {q10-q11}, [r1, :64]!
++ vld1.8 {d24}, [r1, :64], r3
++ sub r1, #32
+ vext.8 q0, q10, q11, #7
+ vext.8 q1, q11, q12, #7
+ // load c
+- vld1.8 {q10-q11}, [r1]
+- add r1, #32
+- vld1.8 {q12}, [r1], r3
+- sub r1, #32
+- vext.8 q4, q10, q11, #8
+- vext.8 q5, q11, q12, #8
+- vext.8 q2, q10, q11, #7
+-1: subs r4, #1
++ vld1.8 {d9}, [r1, :64]!
++ vld1.8 {q2-q3}, [r1, :64], r3
++ sub r1, #8
++ vext.8 q4, q4, q2, #15
++1: subs r12, #1
+ // load b
+- vld1.8 {q10-q11}, [r1]
+- add r1, #32
+- vld1.8 {q12}, [r1], r3
+- sub r1, #32
++ vld1.8 {q10-q11}, [r1, :64]!
++ vld1.8 {q12}, [r1, :64], r3
++ sub r1, #32
+ vext.8 q8, q10, q11, #9
+ vext.8 q9, q11, q12, #9
+- vext.8 q14, q10, q11, #8
+- vext.8 q15, q11, q12, #8
+- vext.8 q3, q10, q11, #7
++ vext.8 q6, q10, q11, #8
++ vext.8 q7, q11, q12, #8
++ vext.8 q5, q10, q11, #7
+ edge_w32_body
+ // inputs for next loop iteration
+ // a
+- vmov.8 q0, q2
+- vext.8 q1, q4, q5, #15
++ vmov.8 q0, q4
++ vext.8 q1, q2, q3, #15
+ // c
+- vmov.8 q4, q14
+- vmov.8 q5, q15
+- vmov.8 q2, q3
+- bne 1b
+- vpop {d8-d15}
+- pop {r4-r8}
+- bx lr
++ vmov.8 q2, q6
++ vmov.8 q3, q7
++ vmov.8 q4, q5
++ bne 1b
++ vpop {d8-d15}
++ bx lr
+ endfunc
+
+ function ff_hevc_sao_edge_eo3_w32_neon_8, export=1
+- push {r4-r8}
+- ldr r4, [sp, #20] // height
+- ldr r5, [sp, #24] // sao_offset_val_table
+- ldr r6, =0x03
+- ldr r7, [r5]
+- add r5, #4
+- sub r1, r3
+- ldr r5, [r5]
+- sub r1, #8
+- vpush {d8-d15}
++ init_edge_32
++ sub r1, r3
+ // load a
+- vld1.8 {q10-q11}, [r1]
+- add r1, #32
+- vld1.8 {q12}, [r1], r3
+- sub r1, #32
+- vext.8 q0, q10, q11, #9
+- vext.8 q1, q11, q12, #9
++ vld1.8 {q10-q11}, [r1, :64]!
++ vld1.8 {d24}, [r1, :64], r3
++ sub r1, #32
++ vext.8 q0, q10, q11, #1
++ vext.8 q1, q11, q12, #1
+ // load c
+- vld1.8 {q10-q11}, [r1]
+- add r1, #32
+- vld1.8 {q12}, [r1], r3
+- sub r1, #32
+- vext.8 q4, q10, q11, #8
+- vext.8 q5, q11, q12, #8
+- vext.8 q2, q12, q11, #8
+-1: subs r4, #1
++ vld1.8 {q2-q3}, [r1, :64]!
++ vld1.8 {d30}, [r1, :64], r3
++ sub r1, #40
++1: subs r12, #1
+ // load b
+- vld1.8 {q10-q11}, [r1]
+- add r1, #32
+- vld1.8 {q12}, [r1], r3
+- sub r1, #32
++ vld1.8 {q10-q11}, [r1, :64]!
++ vld1.8 {q12}, [r1, :64], r3
++ sub r1, #32
+ vext.8 q8, q10, q11, #7
+ vext.8 q9, q11, q12, #7
+- vext.8 q3, q12, q10, #7
++ vext.8 q14, q12, q10, #7
+ edge_w32_body
+ // inputs for next loop iteration
+ // a
+- vext.8 q0, q4, q5, #1
+- vext.8 q1, q5, q2, #1
++ vext.8 q0, q2, q3, #1
++ vext.8 q1, q3, q15, #1
+ // c
+- vext.8 q4, q8, q9, #1
+- vext.8 q5, q9, q3, #1
+- vext.8 q2, q3, q1, #1
+- bne 1b
+- vpop {d8-d15}
+- pop {r4-r8}
+- bx lr
++ vext.8 q2, q8, q9, #1
++ vext.8 q3, q9, q14, #1
++ vext.8 d30, d28, d2, #1
++ bne 1b
++ bx lr
+ endfunc
+
+--
+2.5.0
+
+
+From 016c39d46b86830204a4519590332d2a38f7ee51 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Thu, 8 Jan 2015 09:58:55 +0200
+Subject: [PATCH 7/9] small optimization to SAO BAND. correct path for
+ bit_depth_template.c
+
+---
+ libavcodec/arm/hevcdsp_init_neon.c | 2 +-
+ libavcodec/arm/hevcdsp_sao_neon.S | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index 8d6e863..385c35d 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -23,7 +23,7 @@
+ #include "libavcodec/hevcdsp.h"
+ #include "hevcdsp_arm.h"
+ #include "libavcodec/avcodec.h"
+-#include "../bit_depth_template.c"
++#include "libavcodec/bit_depth_template.c"
+
+ void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+ void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index 5fc482b..710b32b 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -26,12 +26,12 @@
+ pld [r1]
+ vld1.8 {q0, q1}, [r12] // offset table
+ ldr r12, [sp, #4] // height
++ vmov.u8 q14, #128
+ .endm
+
+ .macro sao_band_32
+ vshr.u8 q8, q2, #3
+ vshr.u8 q9, q3, #3
+- vmov.u8 q14, #128
+ vtbl.8 d16, {q0, q1}, d16
+ vtbl.8 d17, {q0, q1}, d17
+ vtbl.8 d18, {q0, q1}, d18
+--
+2.5.0
+
+
+From 579f1584d688e1ac24fb7d22697e2a7b64f62e8e Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Fri, 9 Jan 2015 10:28:52 +0200
+Subject: [PATCH 8/9] Added height check for SAO NEON optimizations. Faster SAO
+ band NEON Some reordering to use NEON pipelines more efficiently
+
+---
+ libavcodec/arm/hevcdsp_init_neon.c | 12 +++-
+ libavcodec/arm/hevcdsp_sao_neon.S | 142 ++++++++++++++++++++++---------------
+ 2 files changed, 93 insertions(+), 61 deletions(-)
+
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index 385c35d..6d0689c 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -176,6 +176,7 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
+ int8_t offset_table[32] = { 0 };
+ int k, y, x;
+ int shift = 3; // BIT_DEPTH - 5
++ int cwidth = 0;
+
+ stride_src /= sizeof(pixel);
+ stride_dst /= sizeof(pixel);
+@@ -183,7 +184,10 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
+ for (k = 0; k < 4; k++)
+ offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];
+
+- switch(width){
++ if (height % 8 == 0)
++ cwidth = width;
++
++ switch(cwidth){
+ case 8:
+ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
+ break;
+@@ -223,15 +227,19 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
+ pixel *src = (pixel *)_src;
+ int a_stride, b_stride;
+ int x, y;
++ int cwidth = 0;
+
+ for (x = 0; x < 5; x++) {
+ sao_offset_val[x] = _sao_offset_val[edge_idx[x]];
+ }
+
++ if (height % 8 == 0)
++ cwidth = width;
++
+ stride_src /= sizeof(pixel);
+ stride_dst /= sizeof(pixel);
+
+- switch (width) {
++ switch (cwidth) {
+ case 32:
+ switch(eo) {
+ case 0:
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index 710b32b..08f50b8 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -26,36 +26,59 @@
+ pld [r1]
+ vld1.8 {q0, q1}, [r12] // offset table
+ ldr r12, [sp, #4] // height
+- vmov.u8 q14, #128
++ vmov.u8 q3, #128
+ .endm
+
+-.macro sao_band_32
+- vshr.u8 q8, q2, #3
+- vshr.u8 q9, q3, #3
+- vtbl.8 d16, {q0, q1}, d16
+- vtbl.8 d17, {q0, q1}, d17
+- vtbl.8 d18, {q0, q1}, d18
+- vtbl.8 d19, {q0, q1}, d19
+- vadd.s8 q2, q14
+- vadd.s8 q3, q14
+- vqadd.s8 q2, q8
+- vqadd.s8 q3, q9
+- vsub.s8 q2, q14
+- vsub.s8 q3, q14
++// 128 in q3
++// input q8 - q11
++// 32 cycles
++.macro sao_band_64
++ vshr.u8 q12, q8, #3
++ vshr.u8 q13, q9, #3
++ vshr.u8 q14, q10, #3
++ vshr.u8 q15, q11, #3
++ vtbl.8 d24, {d0, d1, d2, d3}, d24
++ vadd.s8 q8, q3
++ vtbl.8 d25, {d0, d1, d2, d3}, d25
++ vadd.s8 q9, q3
++ vtbl.8 d26, {d0, d1, d2, d3}, d26
++ vadd.s8 q10, q3
++ vtbl.8 d27, {d0, d1, d2, d3}, d27
++ vadd.s8 q11, q3
++ vtbl.8 d28, {d0, d1, d2, d3}, d28
++ vqadd.s8 q8, q12
++ vtbl.8 d29, {d0, d1, d2, d3}, d29
++ vqadd.s8 q9, q13
++ vtbl.8 d30, {d0, d1, d2, d3}, d30
++ vqadd.s8 q10, q14
++ vtbl.8 d31, {d0, d1, d2, d3}, d31
++ vqadd.s8 q11, q15
++ vsub.s8 q8, q3
++ vsub.s8 q9, q3
++ vsub.s8 q10, q3
++ vsub.s8 q11, q3
+ .endm
+
+ function ff_hevc_sao_band_w8_neon_8, export=1
+ init_sao_band
+-1: subs r12, #4
+- vld1.8 {d4}, [r1, :64], r3
+- vld1.8 {d5}, [r1, :64], r3
+- vld1.8 {d6}, [r1, :64], r3
+- vld1.8 {d7}, [r1, :64], r3
+- sao_band_32
+- vst1.8 {d4}, [r0, :64], r2
+- vst1.8 {d5}, [r0, :64], r2
+- vst1.8 {d6}, [r0, :64], r2
+- vst1.8 {d7}, [r0, :64], r2
++1: subs r12, #8
++ vld1.8 {d16}, [r1, :64], r3
++ vld1.8 {d17}, [r1, :64], r3
++ vld1.8 {d18}, [r1, :64], r3
++ vld1.8 {d19}, [r1, :64], r3
++ vld1.8 {d20}, [r1, :64], r3
++ vld1.8 {d21}, [r1, :64], r3
++ vld1.8 {d22}, [r1, :64], r3
++ vld1.8 {d23}, [r1, :64], r3
++ sao_band_64
++ vst1.8 {d16}, [r0, :64], r2
++ vst1.8 {d17}, [r0, :64], r2
++ vst1.8 {d18}, [r0, :64], r2
++ vst1.8 {d19}, [r0, :64], r2
++ vst1.8 {d20}, [r0, :64], r2
++ vst1.8 {d21}, [r0, :64], r2
++ vst1.8 {d22}, [r0, :64], r2
++ vst1.8 {d23}, [r0, :64], r2
+ bne 1b
+
+ bx lr
+@@ -63,12 +86,16 @@ endfunc
+
+ function ff_hevc_sao_band_w16_neon_8, export=1
+ init_sao_band
+-1: subs r12, #2
+- vld1.8 {q2}, [r1, :128], r3
+- vld1.8 {q3}, [r1, :128], r3
+- sao_band_32
+- vst1.8 {q2}, [r0, :128], r2
+- vst1.8 {q3}, [r0, :128], r2
++1: subs r12, #4
++ vld1.8 {q8}, [r1, :128], r3
++ vld1.8 {q9}, [r1, :128], r3
++ vld1.8 {q10}, [r1, :128], r3
++ vld1.8 {q11}, [r1, :128], r3
++ sao_band_64
++ vst1.8 {q8}, [r0, :128], r2
++ vst1.8 {q9}, [r0, :128], r2
++ vst1.8 {q10}, [r0, :128], r2
++ vst1.8 {q11}, [r0, :128], r2
+ bne 1b
+
+ bx lr
+@@ -76,10 +103,12 @@ endfunc
+
+ function ff_hevc_sao_band_w32_neon_8, export=1
+ init_sao_band
+-1: subs r12, #1
+- vld1.8 {q2-q3}, [r1, :128], r3
+- sao_band_32
+- vst1.8 {q2-q3}, [r0, :128], r2
++1: subs r12, #2
++ vld1.8 {q8-q9}, [r1, :128], r3
++ vld1.8 {q10-q11}, [r1, :128], r3
++ sao_band_64
++ vst1.8 {q8-q9}, [r0, :128], r2
++ vst1.8 {q10-q11}, [r0, :128], r2
+ bne 1b
+
+ bx lr
+@@ -89,13 +118,12 @@ function ff_hevc_sao_band_w64_neon_8, export=1
+ init_sao_band
+ 1: subs r12, #1
+ pld [r1, r3]
+- vld1.8 {q2-q3}, [r1, :128]!
+- sao_band_32
+- vst1.8 {q2-q3}, [r0, :128]!
+- vld1.8 {q2-q3}, [r1, :128], r3
++ vld1.8 {q8-q9}, [r1, :128]!
++ vld1.8 {q10-q11}, [r1, :128], r3
+ sub r1, #32
+- sao_band_32
+- vst1.8 {q2-q3}, [r0, :128], r2
++ sao_band_64
++ vst1.8 {q8-q9}, [r0, :128]!
++ vst1.8 {q10-q11}, [r0, :128], r2
+ sub r0, #32
+ bne 1b
+
+@@ -121,7 +149,6 @@ endfunc
+ vcgt.u8 q1, q5, q9
+ vcgt.u8 q15, q9, q5
+ vsub.s8 q0, q14, q0 // diff1
+-
+ vsub.s8 q1, q15, q1
+
+ vadd.s8 q0, q12 //diff0 + diff1
+@@ -157,27 +184,25 @@ endfunc
+
+ vmov.u8 q15, #128 // s8 #-128
+ vtbl.8 d0, {d24}, d0
++ vadd.s8 q13, q4, q15
+ vtbl.8 d1, {d24}, d1
++ vadd.s8 q14, q5, q15
+ vtbl.8 d2, {d24}, d2
++ vqadd.s8 q0, q13
+ vtbl.8 d3, {d24}, d3
++ vqadd.s8 q1, q14
+ vtbl.8 d4, {d24}, d4
++ vadd.s8 q13, q6, q15
+ vtbl.8 d5, {d24}, d5
++ vadd.s8 q14, q7, q15
+ vtbl.8 d6, {d24}, d6
++ vqadd.s8 q2, q13
+ vtbl.8 d7, {d24}, d7
+-
+- vadd.s8 q12, q4, q15
+- vadd.s8 q13, q5, q15
+- vadd.s8 q14, q6, q15
+- vadd.s8 q15, q7, q15
+- vqadd.s8 q12, q0
+- vqadd.s8 q15, q3
+- vmov.u8 q3, #128 // s8 #-128
+- vqadd.s8 q13, q1
+- vqadd.s8 q14, q2
+- vsub.s8 q0, q12, q3
+- vsub.s8 q1, q13, q3
+- vsub.s8 q2, q14, q3
+- vsub.s8 q3, q15, q3
++ vqadd.s8 q3, q14
++ vsub.s8 q0, q15
++ vsub.s8 q1, q15
++ vsub.s8 q2, q15
++ vsub.s8 q3, q15
+ vst1.8 {q0-q1}, [r0, :128]!
+ vst1.8 {q2-q3}, [r0, :128], r2
+ sub r0, #32
+@@ -342,13 +367,12 @@ endfunc
+
+ vmov.u8 q10, #128
+ vtbl.8 d0, {d31}, d0
++ vadd.s8 q11, q2, q10
+ vtbl.8 d1, {d31}, d1
++ vadd.s8 q12, q3, q10
+ vtbl.8 d2, {d31}, d2
++ vqadd.s8 q11, q0
+ vtbl.8 d3, {d31}, d3
+-
+- vadd.s8 q11, q2, q10
+- vadd.s8 q12, q3, q10
+- vqadd.s8 q11, q0
+ vqadd.s8 q12, q1
+ vsub.s8 q0, q11, q10
+ vsub.s8 q1, q12, q10
+--
+2.5.0
+
+
+From 026bac1824e4936e948e6b1efec82868c520ea66 Mon Sep 17 00:00:00 2001
+From: Seppo Tomperi
+Date: Mon, 2 Feb 2015 16:08:27 +0200
+Subject: [PATCH 9/9] Further SAO NEON optimisations
+
+---
+ libavcodec/arm/hevcdsp_init_neon.c | 16 +--
+ libavcodec/arm/hevcdsp_sao_neon.S | 224 +++++++++++++++++++------------------
+ 2 files changed, 124 insertions(+), 116 deletions(-)
+
+diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
+index 6d0689c..e5da7e9 100644
+--- a/libavcodec/arm/hevcdsp_init_neon.c
++++ b/libavcodec/arm/hevcdsp_init_neon.c
+@@ -45,10 +45,10 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs,
+ void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs,
+ ptrdiff_t stride);
+
+-void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
+-void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
+-void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
+-void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
++void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
++void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
++void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
++void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
+
+ void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
+ void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
+@@ -189,16 +189,16 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
+
+ switch(cwidth){
+ case 8:
+- ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
++ ff_hevc_sao_band_w8_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
+ break;
+ case 16:
+- ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
++ ff_hevc_sao_band_w16_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
+ break;
+ case 32:
+- ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
++ ff_hevc_sao_band_w32_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
+ break;
+ case 64:
+- ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
++ ff_hevc_sao_band_w64_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
+ break;
+ default:
+ for (y = 0; y < height; y++) {
+diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
+index 08f50b8..9c7808d 100644
+--- a/libavcodec/arm/hevcdsp_sao_neon.S
++++ b/libavcodec/arm/hevcdsp_sao_neon.S
+@@ -22,21 +22,16 @@
+ #include "neon.S"
+
+ .macro init_sao_band
+- ldr r12, [sp, #0] // offset_table address
+ pld [r1]
+- vld1.8 {q0, q1}, [r12] // offset table
+- ldr r12, [sp, #4] // height
++ vld1.8 {q0, q1}, [r2] // offset table
++ ldr r2, [sp, #0] // stride_dst
++ ldr r12, [sp, #4] // height
+ vmov.u8 q3, #128
+ .endm
+
+ // 128 in q3
+ // input q8 - q11
+-// 32 cycles
+ .macro sao_band_64
+- vshr.u8 q12, q8, #3
+- vshr.u8 q13, q9, #3
+- vshr.u8 q14, q10, #3
+- vshr.u8 q15, q11, #3
+ vtbl.8 d24, {d0, d1, d2, d3}, d24
+ vadd.s8 q8, q3
+ vtbl.8 d25, {d0, d1, d2, d3}, d25
+@@ -52,8 +47,8 @@
+ vtbl.8 d30, {d0, d1, d2, d3}, d30
+ vqadd.s8 q10, q14
+ vtbl.8 d31, {d0, d1, d2, d3}, d31
+- vqadd.s8 q11, q15
+ vsub.s8 q8, q3
++ vqadd.s8 q11, q15
+ vsub.s8 q9, q3
+ vsub.s8 q10, q3
+ vsub.s8 q11, q3
+@@ -64,12 +59,16 @@ function ff_hevc_sao_band_w8_neon_8, export=1
+ 1: subs r12, #8
+ vld1.8 {d16}, [r1, :64], r3
+ vld1.8 {d17}, [r1, :64], r3
++ vshr.u8 q12, q8, #3
+ vld1.8 {d18}, [r1, :64], r3
+ vld1.8 {d19}, [r1, :64], r3
++ vshr.u8 q13, q9, #3
+ vld1.8 {d20}, [r1, :64], r3
+ vld1.8 {d21}, [r1, :64], r3
++ vshr.u8 q14, q10, #3
+ vld1.8 {d22}, [r1, :64], r3
+ vld1.8 {d23}, [r1, :64], r3
++ vshr.u8 q15, q11, #3
+ sao_band_64
+ vst1.8 {d16}, [r0, :64], r2
+ vst1.8 {d17}, [r0, :64], r2
+@@ -88,9 +87,13 @@ function ff_hevc_sao_band_w16_neon_8, export=1
+ init_sao_band
+ 1: subs r12, #4
+ vld1.8 {q8}, [r1, :128], r3
++ vshr.u8 q12, q8, #3
+ vld1.8 {q9}, [r1, :128], r3
++ vshr.u8 q13, q9, #3
+ vld1.8 {q10}, [r1, :128], r3
++ vshr.u8 q14, q10, #3
+ vld1.8 {q11}, [r1, :128], r3
++ vshr.u8 q15, q11, #3
+ sao_band_64
+ vst1.8 {q8}, [r0, :128], r2
+ vst1.8 {q9}, [r0, :128], r2
+@@ -105,7 +108,11 @@ function ff_hevc_sao_band_w32_neon_8, export=1
+ init_sao_band
+ 1: subs r12, #2
+ vld1.8 {q8-q9}, [r1, :128], r3
++ vshr.u8 q12, q8, #3
++ vshr.u8 q13, q9, #3
+ vld1.8 {q10-q11}, [r1, :128], r3
++ vshr.u8 q14, q10, #3
++ vshr.u8 q15, q11, #3
+ sao_band_64
+ vst1.8 {q8-q9}, [r0, :128], r2
+ vst1.8 {q10-q11}, [r0, :128], r2
+@@ -119,7 +126,11 @@ function ff_hevc_sao_band_w64_neon_8, export=1
+ 1: subs r12, #1
+ pld [r1, r3]
+ vld1.8 {q8-q9}, [r1, :128]!
++ vshr.u8 q12, q8, #3
++ vshr.u8 q13, q9, #3
+ vld1.8 {q10-q11}, [r1, :128], r3
++ vshr.u8 q14, q10, #3
++ vshr.u8 q15, q11, #3
+ sub r1, #32
+ sao_band_64
+ vst1.8 {q8-q9}, [r0, :128]!
+@@ -129,51 +140,18 @@ function ff_hevc_sao_band_w64_neon_8, export=1
+
+ bx lr
+ endfunc
+-// input
+-// a in q0 - q3
+-// c in q4 - q7
+-// b in q8 - q11
+-// offset table in r7 and r5
+-// output in q0 - q3
+-// clobbers q12 - q15
+-.macro edge_w64_body
+- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
+- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
+- vcgt.u8 q13, q5, q1
+- vcgt.u8 q1, q1, q5
+- vsub.s8 q12, q0, q12 // diff0
+- vcgt.u8 q0, q4, q8 // c > b
+- vsub.s8 q13, q1, q13
+-
+- vcgt.u8 q14, q8, q4 // b > c
+- vcgt.u8 q1, q5, q9
+- vcgt.u8 q15, q9, q5
+- vsub.s8 q0, q14, q0 // diff1
+- vsub.s8 q1, q15, q1
+
+- vadd.s8 q0, q12 //diff0 + diff1
+- vadd.s8 q1, q13
+-
+- vcgt.u8 q14, q6, q2
+- vcgt.u8 q2, q2, q6
+- vcgt.u8 q15, q7, q3
+- vcgt.u8 q3, q3, q7
+-
+- vsub.s8 q14, q2, q14
+- vcgt.u8 q2, q6, q10
+- vsub.s8 q15, q3, q15
+-
+- vcgt.u8 q12, q10, q6
+- vcgt.u8 q3, q7, q11
+- vcgt.u8 q13, q11, q7
+- vsub.s8 q2, q12, q2
+- vsub.s8 q3, q13, q3
++.macro diff32 out0, out1, tmp0, tmp1, in0, in1, in2, in3
++ vcgt.u8 \out0, \in2, \in0 // c > a -> -1 , otherwise 0
++ vcgt.u8 \tmp0, \in0, \in2 // a > c -> -1 , otherwise 0
++ vcgt.u8 \out1, \in3, \in1 // c > a -> -1 , otherwise 0 part 2
++ vcgt.u8 \tmp1, \in1, \in3 // a > c -> -1 , otherwise 0 part 2
++ vsub.s8 \out0, \tmp0, \out0 // diff0
++ vsub.s8 \out1, \tmp1, \out1 // diff0 part 2
++.endm
+
++.macro table64
+ vmov.s8 q13, #2 // 2 to all elements
+-
+- vadd.s8 q2, q14
+- vadd.s8 q3, q15
+-
+ vmov.32 d24[0], r4 // load offset table from general registers
+ vmov.32 d24[1], r5 // load rest of offset table
+
+@@ -208,6 +186,28 @@ endfunc
+ sub r0, #32
+ .endm
+
++// input
++// a in q0 - q3
++// c in q4 - q7
++// b in q8 - q11
++// offset table in r7 and r5
++// output in q0 - q3
++// clobbers q12 - q15
++.macro edge_w64_body
++ diff32 q12, q13, q0, q1, q0, q1, q4, q5
++ diff32 q0, q1, q14, q15, q8, q9, q4, q5
++
++ vadd.s8 q0, q12 //diff0 + diff1
++ vadd.s8 q1, q13
++
++ diff32 q14, q15, q2, q3, q2, q3, q6, q7
++ diff32 q2, q3, q12, q13, q10, q11, q6, q7
++
++ vadd.s8 q2, q14
++ vadd.s8 q3, q15
++ table64
++.endm
++
+ .macro init_edge_64
+ push {r4-r5}
+ ldr r12, [sp, #8] // height
+@@ -334,38 +334,23 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
+ bx lr
+ endfunc
+
+-// inputs:
+-// a in q0, q1
+-// c in q2, q3
+-// b in q8, q9
+-// offset table in d31
+-// clobbered registers q0, q1, q10, q11, q12, q13
+-// output q0, q1
+-.macro edge_w32_body
+- vcgt.u8 q12, q2, q0 // c > a -> -1 , otherwise 0
+- vcgt.u8 q0, q0, q2 // a > c -> -1 , otherwise 0
+- vcgt.u8 q13, q3, q1
+- vcgt.u8 q1, q1, q3
+-
+- vsub.s8 q12, q0, q12 // diff0
+- vcgt.u8 q0, q2, q8 // c > b
+- vsub.s8 q13, q1, q13 // diff0 part 2
+-
+- vcgt.u8 q10, q8, q2 // b > c
+- vcgt.u8 q1, q3, q9
+- vcgt.u8 q11, q9, q3
+-
+- vsub.s8 q0, q10, q0 // diff1
+-
+- vmov.s8 q10, #2 // 2 to all elements
+- vsub.s8 q1, q11, q1 // diff1 part 2
+- vadd.s8 q0, q12 //diff0 + diff1
+- vadd.s8 q1, q13
++.macro init_edge_32
++ ldr r12, [sp, #4] // sao_offset_val_table
++ vld1.32 {d31}, [r12]
++ ldr r12, [sp] // height
++.endm
+
+- vadd.s8 q0, q10
+- vadd.s8 q1, q10
++.macro diff out0, tmp0, in0, in1
++ vcgt.u8 \out0, \in1, \in0 // c > a -> -1 , otherwise 0
++ vcgt.u8 \tmp0, \in0, \in1 // a > c -> -1 , otherwise 0
++ vsub.s8 \out0, \tmp0, \out0 // diff0
++.endm
+
+- vmov.u8 q10, #128
++.macro table32
++ vmov.s8 q10, #2
++ vadd.s8 q0, q10
++ vadd.s8 q1, q10
++ vmov.s8 q10, #128
+ vtbl.8 d0, {d31}, d0
+ vadd.s8 q11, q2, q10
+ vtbl.8 d1, {d31}, d1
+@@ -373,56 +358,68 @@ endfunc
+ vtbl.8 d2, {d31}, d2
+ vqadd.s8 q11, q0
+ vtbl.8 d3, {d31}, d3
+- vqadd.s8 q12, q1
+- vsub.s8 q0, q11, q10
+- vsub.s8 q1, q12, q10
++ vqadd.s8 q12, q1
++ vsub.s8 q0, q11, q10
++ vsub.s8 q1, q12, q10
+ vst1.8 {q0-q1}, [r0, :128], r2
+ .endm
+
+-.macro init_edge_32
+- ldr r12, [sp, #4] // sao_offset_val_table
+- vld1.32 {d31}, [r12]
+- ldr r12, [sp] // height
+-.endm
+-
+ function ff_hevc_sao_edge_eo0_w32_neon_8, export=1
+ init_edge_32
+- sub r1, #4 // load 4 extra bytes
++ vpush {q4-q7}
++ sub r1, #4
+ 1: subs r12, #1
+- vld1.32 d3[1], [r1]!
+- vld1.8 {q2-q3}, [r1, :128]! // c
+- vld1.32 d20[0], [r1], r3
+- sub r1, #36
++ vld1.8 {q13-q14}, [r1]!
++ vld1.32 d30, [r1], r3
++ sub r1, #32
+ // a
+- vext.8 q0, q1, q2, #15
+- vext.8 q1, q2, q3, #15
+- // b
+- vext.8 q8, q2, q3, #1
+- vext.8 q9, q3, q10, #1
+- edge_w32_body
++ vext.8 q0, q13, q14, #3
++ vext.8 q1, q14, q15, #3
++ vshr.u64 d24, d30, #24
++ // c
++ vext.8 q2, q13, q14, #4
++ vext.8 q3, q14, q15, #4
++ vshr.u64 d16, d30, #32
++ // diff0
++ diff32 q13, q14, q4, q5, q0, q1, q2, q3
++ diff d18, d25, d24, d16
++ // -diff1
++ vext.s8 q0, q13, q14, #1
++ vext.s8 q1, q14, q9, #1
++
++ vsub.s8 q0, q13, q0 //diff0 + diff1
++ vsub.s8 q1, q14, q1
++ table32
+ bne 1b
++ vpop {q4-q7}
++
+ bx lr
+ endfunc
+
+ function ff_hevc_sao_edge_eo1_w32_neon_8, export=1
+ init_edge_32
++ vpush {q4-q7}
+ // load a
+ sub r1, r3
+ vld1.8 {q0-q1}, [r1, :128], r3
+ // load c
+ vld1.8 {q2-q3}, [r1, :128], r3
++ diff32 q12, q13, q0, q1, q0, q1, q2, q3 // CMP ( c, a )
+ 1: subs r12, #1
+ // load b
+ vld1.8 {q8-q9}, [r1, :128], r3
+- edge_w32_body
+- // inputs for next loop iteration
+- // a
+- vmov.64 q0, q2
+- vmov.64 q1, q3
++ diff32 q4, q5, q10, q11, q8, q9, q2, q3 // CMP ( c, b )
++ vadd.s8 q0, q4, q12 //diff0 + diff1
++ vadd.s8 q1, q5, q13
++ table32
++ // CMP ( c, a )
++ vneg.s8 q12, q4
++ vneg.s8 q13, q5
+ // c
+ vmov.64 q2, q8
+ vmov.64 q3, q9
+ bne 1b
++ vpop {q4-q7}
+ bx lr
+ endfunc
+
+@@ -452,7 +449,11 @@ function ff_hevc_sao_edge_eo2_w32_neon_8, export=1
+ vext.8 q6, q10, q11, #8
+ vext.8 q7, q11, q12, #8
+ vext.8 q5, q10, q11, #7
+- edge_w32_body
++ diff32 q12, q13, q0, q1, q0, q1, q2, q3
++ diff32 q0, q1, q10, q11, q8, q9, q2, q3
++ vadd.s8 q0, q12 //diff0 + diff1
++ vadd.s8 q1, q13
++ table32
+ // inputs for next loop iteration
+ // a
+ vmov.8 q0, q4
+@@ -487,7 +488,14 @@ function ff_hevc_sao_edge_eo3_w32_neon_8, export=1
+ vext.8 q8, q10, q11, #7
+ vext.8 q9, q11, q12, #7
+ vext.8 q14, q12, q10, #7
+- edge_w32_body
++
++ diff32 q12, q13, q0, q1, q0, q1, q2, q3
++ diff32 q0, q1, q10, q11, q8, q9, q2, q3
++
++ vadd.s8 q0, q12 //diff0 + diff1
++ vadd.s8 q1, q13
++ table32
++
+ // inputs for next loop iteration
+ // a
+ vext.8 q0, q2, q3, #1
+--
+2.5.0
+
+
diff --git a/projects/RPi2/patches/ffmpeg/ffmpeg-001-jarvis-rbp-backports.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1003-pfcd_hevc_optimisations.patch
similarity index 87%
rename from projects/RPi2/patches/ffmpeg/ffmpeg-001-jarvis-rbp-backports.patch
rename to packages/multimedia/ffmpeg/patches/ffmpeg-99.1003-pfcd_hevc_optimisations.patch
index 30061d6d00..a48d81a1a3 100644
--- a/projects/RPi2/patches/ffmpeg/ffmpeg-001-jarvis-rbp-backports.patch
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1003-pfcd_hevc_optimisations.patch
@@ -1,3810 +1,4 @@
-From ff289b3678b3b102f76c0fc0ffc802e3c8026fdb Mon Sep 17 00:00:00 2001
-From: Deborah Crook
-Date: Thu, 5 Mar 2015 19:48:43 +0000
-Subject: [PATCH] Discard data before VO/VOL in mpeg-4 over mpegts
-
----
- libavcodec/mpeg4video_parser.c | 26 ++++++++++++++++++++++----
- 1 file changed, 22 insertions(+), 4 deletions(-)
-
-diff --git a/libavcodec/mpeg4video_parser.c b/libavcodec/mpeg4video_parser.c
-index aa5e87a..0d8b15a 100644
---- a/libavcodec/mpeg4video_parser.c
-+++ b/libavcodec/mpeg4video_parser.c
-@@ -43,18 +43,32 @@ int ff_mpeg4_find_frame_end(ParseContext *pc, const uint8_t *buf, int buf_size)
- state = pc->state;
-
- i = 0;
-- if (!vop_found) {
-+ if (vop_found < 0) {
-+ for (i = 0; i < buf_size; i++) {
-+ state = (state << 8) | buf[i];
-+ if (state >= 0x100 && state <= 0x12f) {
-+ i++;
-+ vop_found = 0;
-+ break;
-+ }
-+ }
-+ }
-+
-+ if (vop_found == 0)
-+ vop_found = 1;
-+
-+ if (vop_found == 1) {
- for (i = 0; i < buf_size; i++) {
- state = (state << 8) | buf[i];
- if (state == 0x1B6) {
- i++;
-- vop_found = 1;
-+ vop_found = 2;
- break;
- }
- }
- }
-
-- if (vop_found) {
-+ if (vop_found == 2) {
- /* EOF considered as end of frame */
- if (buf_size == 0)
- return 0;
-@@ -133,12 +147,16 @@ static int mpeg4video_parse(AVCodecParserContext *s,
- ParseContext *pc = s->priv_data;
- int next;
-
-+ if (pc->frame_start_found == 0 && !avctx->extradata)
-+ pc->frame_start_found = -1;
-+
- if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
- next = buf_size;
- } else {
- next = ff_mpeg4_find_frame_end(pc, buf, buf_size);
-
-- if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
-+ if (pc->frame_start_found < 0 ||
-+ ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
- *poutbuf = NULL;
- *poutbuf_size = 0;
- return buf_size;
---
-2.1.4
-From 29c3327a0d72a7e872ff170363cfe5ed13bca5d0 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Tue, 22 Dec 2015 18:10:24 +0000
-Subject: [PATCH] hevcdsp: ARM NEON optimized epel functions
-
----
- libavcodec/arm/Makefile | 1 +
- libavcodec/arm/hevcdsp_epel_neon.S | 334 +++++++++++++++++++++++++++++++++++++
- libavcodec/arm/hevcdsp_init_neon.c | 23 +++
- 3 files changed, 358 insertions(+)
- create mode 100644 libavcodec/arm/hevcdsp_epel_neon.S
-
-diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
-index cdd35b0..6051ec8 100644
---- a/libavcodec/arm/Makefile
-+++ b/libavcodec/arm/Makefile
-@@ -131,6 +131,7 @@ NEON-OBJS-$(CONFIG_DCA_DECODER) += arm/dcadsp_neon.o \
- arm/synth_filter_neon.o
- NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \
- arm/hevcdsp_deblock_neon.o \
-+ arm/hevcdsp_epel_neon.o \
- arm/hevcdsp_idct_neon.o \
- arm/hevcdsp_qpel_neon.o
- NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o
-diff --git a/libavcodec/arm/hevcdsp_epel_neon.S b/libavcodec/arm/hevcdsp_epel_neon.S
-new file mode 100644
-index 0000000..516ae5b
---- /dev/null
-+++ b/libavcodec/arm/hevcdsp_epel_neon.S
-@@ -0,0 +1,334 @@
-+/*
-+ * Copyright (c) 2014 - 2015 Seppo Tomperi
-+ *
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "libavutil/arm/asm.S"
-+#include "neon.S"
-+
-+#define MAX_PB_SIZE #64
-+
-+.macro vextin_d4
-+ vld1.8 {q10}, [r1], r2
-+ vmov d16, d20
-+ vext.8 d17, d20, d21, #1
-+ vext.8 d18, d20, d21, #2
-+ vext.8 d19, d20, d21, #3
-+.endm
-+
-+.macro vextin_d4_8
-+ vld1.8 d16, [r1], r2
-+ vext.8 d17, d16, d16, #1
-+ vext.8 d18, d16, d16, #2
-+ vext.8 d19, d16, d16, #3
-+.endm
-+
-+.macro load_coeffs_16b coeffs
-+ ldr \coeffs, [\coeffs]
-+ vdup.i8 d0, \coeffs
-+ lsr \coeffs, #8
-+ vdup.i8 d1, \coeffs
-+ lsr \coeffs, #8
-+ vdup.i8 d2, \coeffs
-+ lsr \coeffs, #8
-+ vdup.i8 d3, \coeffs
-+.endm
-+
-+.macro epel_filter_16b out=q12
-+ vmull.u8 q3, d16, d0
-+ vmull.u8 q11, d19, d3
-+ vmull.u8 \out, d17, d1
-+ vmull.u8 q10, d18, d2
-+ vadd.s16 q3, q11
-+ vadd.s16 \out, q10
-+ vsub.s16 \out, q3
-+.endm
-+
-+.macro load_coeffs_32b coeffs
-+ ldr \coeffs, [\coeffs]
-+ vmov.i64 d4, #0
-+ vmov.8 d4[0], \coeffs
-+ lsr \coeffs, #8
-+ vmov.8 d4[2], \coeffs
-+ lsr \coeffs, #8
-+ vmov.8 d4[4], \coeffs
-+ lsr \coeffs, #8
-+ vmov.8 d4[6], \coeffs
-+.endm
-+
-+.macro epel_filter_32b
-+ vmull.s16 q3, d24, d4[0] //q12
-+ vmull.s16 q4, d25, d4[0]
-+ vmull.s16 q5, d30, d4[3] //q15
-+ vmull.s16 q6, d31, d4[3]
-+
-+ vmull.s16 q7, d26, d4[1] // q13
-+ vmull.s16 q8, d27, d4[1]
-+ vmull.s16 q9, d28, d4[2] // q14
-+ vmull.s16 q10, d29, d4[2]
-+ vadd.s32 q3, q5
-+ vadd.s32 q4, q6
-+ vadd.s32 q7, q9
-+ vadd.s32 q8, q10
-+ vsub.s32 q7, q3
-+ vsub.s32 q8, q4
-+ vqshrn.s32 d6, q7, #6
-+ vqshrn.s32 d7, q8, #6
-+.endm
-+
-+.macro epel_filter_32b_4
-+ vmull.s16 q3, d24, d4[0] //q12
-+ vmull.s16 q5, d30, d4[3] //q15
-+ vmull.s16 q7, d26, d4[1] // q13
-+ vmull.s16 q9, d28, d4[2] // q14
-+ vadd.s32 q3, q5
-+ vadd.s32 q7, q9
-+ vsub.s32 q7, q3
-+ vqshrn.s32 d6, q7, #6
-+.endm
-+
-+function ff_hevc_put_epel_h_neon_8, export=1
-+ push {r4-r7}
-+ mov r4, MAX_PB_SIZE
-+ ldr r7, [sp, #16] // mx
-+ ldr r5, [sp, #24] // width
-+ sub r7, #1
-+ lsl r7, #2
-+ vpush {d8-d15}
-+ adrl r12, epel_coeffs
-+ add r7, r12
-+ sub r1, #1
-+ lsl r4, #1
-+ load_coeffs_16b r7
-+ mov r12, r3
-+ mov r6, r0
-+ mov r7, r1
-+ cmp r5, #6
-+ bgt 8f
-+ cmp r5, #4
-+ blt 2f
-+ b 4f
-+8: subs r3, #1
-+ pld [r1]
-+ vextin_d4
-+ epel_filter_16b
-+ vst1.16 {q12}, [r0], r4
-+ bne 8b
-+ subs r5, #8
-+ beq 99f
-+ mov r3, r12
-+ add r6, #16
-+ mov r0, r6
-+ add r7, #8
-+ mov r1, r7
-+ cmp r5, #4
-+ bgt 8b
-+4: subs r3, #1
-+ pld [r1]
-+ vextin_d4_8
-+ epel_filter_16b
-+ vst1.16 d24, [r0], r4
-+ bne 4b
-+ subs r5, #4
-+ beq 99f
-+ mov r3, r12
-+ add r6, #8
-+ mov r0, r6
-+ add r7, #4
-+ mov r1, r7
-+2: subs r3, #1
-+ pld [r1]
-+ vextin_d4_8
-+ epel_filter_16b
-+ vst1.32 d24[0], [r0], r4
-+ bne 2b
-+99: vpop {d8-d15}
-+ pop {r4-r7}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_put_epel_v_neon_8, export=1
-+ push {r4-r7}
-+ mov r4, MAX_PB_SIZE
-+ ldr r7, [sp, #20] // my
-+ ldr r5, [sp, #24] // width
-+ sub r7, #1
-+ lsl r7, #2
-+ vpush {d8-d15}
-+ adrl r12, epel_coeffs
-+ add r7, r12
-+ load_coeffs_16b r7
-+ sub r1, r2
-+ lsl r4, #1
-+ mov r12, r3
-+ mov r6, r0
-+ mov r7, r1
-+0: pld [r1]
-+ vld1.8 {d16}, [r1], r2
-+ pld [r1]
-+ vld1.8 {d17}, [r1], r2
-+ pld [r1]
-+ vld1.8 {d18}, [r1], r2
-+ cmp r5, #6
-+ bgt 8f
-+ cmp r5, #4
-+ blt 2f
-+ b 4f
-+8: pld [r1]
-+ vld1.8 {d19}, [r1], r2
-+ subs r3, #1
-+ epel_filter_16b
-+ vst1.16 {q12}, [r0], r4
-+ vmov d16, d17
-+ vmov d17, d18
-+ vmov d18, d19
-+ bne 8b
-+ subs r5, #8
-+ beq 99f
-+ mov r3, r12
-+ add r6, #16
-+ mov r0, r6
-+ add r7, #8
-+ mov r1, r7
-+ b 0b
-+4: pld [r1]
-+ vld1.8 {d19}, [r1], r2
-+ subs r3, #1
-+ epel_filter_16b
-+ vst1.16 d24, [r0], r4
-+ vmov d16, d17
-+ vmov d17, d18
-+ vmov d18, d19
-+ bne 4b
-+ subs r5, #4
-+ beq 99f
-+ mov r3, r12
-+ add r6, #8
-+ mov r0, r6
-+ add r7, #4
-+ mov r1, r7
-+ b 0b
-+2: pld [r1]
-+ vld1.8 {d19}, [r1], r2
-+ subs r3, #1
-+ epel_filter_16b
-+ vst1.32 d24[0], [r0], r4
-+ vmov d16, d17
-+ vmov d17, d18
-+ vmov d18, d19
-+ bne 2b
-+99: vpop {d8-d15}
-+ pop {r4-r7}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_put_epel_hv_neon_8, export=1
-+ push {r4-r7}
-+ mov r4, MAX_PB_SIZE
-+ ldr r6, [sp, #16] // mx
-+ ldr r7, [sp, #20] // my
-+ ldr r5, [sp, #24] // width
-+ sub r7, #1
-+ lsl r7, #2
-+ vpush {d8-d15}
-+ adrl r12, epel_coeffs
-+ sub r6, #1
-+ lsl r6, #2
-+ add r6, r12 // mx epel coeff offset
-+ add r7, r12
-+ sub r1, #1
-+ sub r1, r2
-+ lsl r4, #1
-+ load_coeffs_16b r6
-+ load_coeffs_32b r7
-+ mov r12, r3
-+ mov r6, r0
-+ mov r7, r1
-+0: pld [r1]
-+ vextin_d4
-+ epel_filter_16b q12
-+ pld [r1]
-+ vextin_d4
-+ epel_filter_16b q13
-+ pld [r1]
-+ vextin_d4
-+ epel_filter_16b q14
-+ cmp r5, #6
-+ bgt 8f
-+ cmp r5, #4
-+ blt 2f
-+ b 4f
-+8: pld [r1]
-+ vextin_d4
-+ epel_filter_16b q15
-+ subs r3, #1
-+ epel_filter_32b
-+ vst1.16 {q3}, [r0], r4
-+ vmov q12, q13
-+ vmov q13, q14
-+ vmov q14, q15
-+ bne 8b
-+ subs r5, #8
-+ beq 99f
-+ mov r3, r12
-+ add r6, #16
-+ mov r0, r6
-+ add r7, #8
-+ mov r1, r7
-+ b 0b
-+4: pld [r1]
-+ vextin_d4_8
-+ epel_filter_16b q15
-+ subs r3, #1
-+ epel_filter_32b_4
-+ vst1.16 d6, [r0], r4
-+ vmov q12, q13
-+ vmov q13, q14
-+ vmov q14, q15
-+ bne 4b
-+ subs r5, #4
-+ beq 99f
-+ mov r3, r12
-+ add r6, #8
-+ mov r0, r6
-+ add r7, #4
-+ mov r1, r7
-+ b 0b
-+2: pld [r1]
-+ vextin_d4_8
-+ epel_filter_16b q15
-+ subs r3, #1
-+ epel_filter_32b_4
-+ vst1.32 d6[0], [r0], r4
-+ vmov q12, q13
-+ vmov q13, q14
-+ vmov q14, q15
-+ bne 2b
-+99: vpop {d8-d15}
-+ pop {r4-r7}
-+ bx lr
-+endfunc
-+
-+epel_coeffs:
-+ .byte 2, 58, 10, 2
-+ .byte 4, 54, 16, 2
-+ .byte 6, 46, 28, 4
-+ .byte 4, 36, 36, 4
-+ .byte 4, 28, 46, 6
-+ .byte 2, 16, 54, 4
-+ .byte 2, 10, 58, 2
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index 5591807..733ff08 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -58,6 +58,15 @@ PUT_PIXELS(ff_hevc_put_pixels_w32_neon_8);
- PUT_PIXELS(ff_hevc_put_pixels_w48_neon_8);
- PUT_PIXELS(ff_hevc_put_pixels_w64_neon_8);
- #undef PUT_PIXELS
-+void ff_hevc_put_epel_h_neon_8(int16_t *dst, uint8_t *src,
-+ ptrdiff_t srcstride, int height,
-+ intptr_t mx, intptr_t my, int width);
-+void ff_hevc_put_epel_v_neon_8(int16_t *dst, uint8_t *src,
-+ ptrdiff_t srcstride, int height,
-+ intptr_t mx, intptr_t my, int width);
-+void ff_hevc_put_epel_hv_neon_8(int16_t *dst, uint8_t *src,
-+ ptrdiff_t srcstride, int height,
-+ intptr_t mx, intptr_t my, int width);
-
- static void (*put_hevc_qpel_neon[4][4])(int16_t *dst, ptrdiff_t dststride, uint8_t *src, ptrdiff_t srcstride,
- int height, int width);
-@@ -201,7 +210,21 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
- c->put_hevc_qpel_bi[x][1][0] = ff_hevc_put_qpel_bi_neon_wrapper;
- c->put_hevc_qpel_bi[x][0][1] = ff_hevc_put_qpel_bi_neon_wrapper;
- c->put_hevc_qpel_bi[x][1][1] = ff_hevc_put_qpel_bi_neon_wrapper;
-+ c->put_hevc_epel[x][1][0] = ff_hevc_put_epel_v_neon_8;
-+ c->put_hevc_epel[x][0][1] = ff_hevc_put_epel_h_neon_8;
-+ c->put_hevc_epel[x][1][1] = ff_hevc_put_epel_hv_neon_8;
- }
-+ c->put_hevc_epel[0][0][0] = ff_hevc_put_pixels_w2_neon_8;
-+ c->put_hevc_epel[1][0][0] = ff_hevc_put_pixels_w4_neon_8;
-+ c->put_hevc_epel[2][0][0] = ff_hevc_put_pixels_w6_neon_8;
-+ c->put_hevc_epel[3][0][0] = ff_hevc_put_pixels_w8_neon_8;
-+ c->put_hevc_epel[4][0][0] = ff_hevc_put_pixels_w12_neon_8;
-+ c->put_hevc_epel[5][0][0] = ff_hevc_put_pixels_w16_neon_8;
-+ c->put_hevc_epel[6][0][0] = ff_hevc_put_pixels_w24_neon_8;
-+ c->put_hevc_epel[7][0][0] = ff_hevc_put_pixels_w32_neon_8;
-+ c->put_hevc_epel[8][0][0] = ff_hevc_put_pixels_w48_neon_8;
-+ c->put_hevc_epel[9][0][0] = ff_hevc_put_pixels_w64_neon_8;
-+
- c->put_hevc_qpel[0][0][0] = ff_hevc_put_pixels_w2_neon_8;
- c->put_hevc_qpel[1][0][0] = ff_hevc_put_pixels_w4_neon_8;
- c->put_hevc_qpel[2][0][0] = ff_hevc_put_pixels_w6_neon_8;
---
-2.5.0
-
-From b0cb307c253d2c9f4b94a54dfc74ddb83af984cc Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Mon, 8 Dec 2014 13:24:40 +0200
-Subject: [PATCH 1/9] added ARM NEON optimized SAO band offset
-
----
- libavcodec/arm/Makefile | 3 +-
- libavcodec/arm/hevcdsp_init_neon.c | 47 +++++++++
- libavcodec/arm/hevcdsp_sao_neon.S | 204 +++++++++++++++++++++++++++++++++++++
- 3 files changed, 253 insertions(+), 1 deletion(-)
- create mode 100644 libavcodec/arm/hevcdsp_sao_neon.S
-
-diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
-index 6051ec8..093a2e8 100644
---- a/libavcodec/arm/Makefile
-+++ b/libavcodec/arm/Makefile
-@@ -133,7 +133,8 @@ NEON-OBJS-$(CONFIG_HEVC_DECODER) += arm/hevcdsp_init_neon.o \
- arm/hevcdsp_deblock_neon.o \
- arm/hevcdsp_epel_neon.o \
- arm/hevcdsp_idct_neon.o \
-- arm/hevcdsp_qpel_neon.o
-+ arm/hevcdsp_qpel_neon.o \
-+ arm/hevcdsp_sao_neon.o
- NEON-OBJS-$(CONFIG_RV30_DECODER) += arm/rv34dsp_neon.o
- NEON-OBJS-$(CONFIG_RV40_DECODER) += arm/rv34dsp_neon.o \
- arm/rv40dsp_neon.o
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index 733ff08..69e2b2c 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -22,6 +22,7 @@
- #include "libavutil/arm/cpu.h"
- #include "libavcodec/hevcdsp.h"
- #include "hevcdsp_arm.h"
-+#include "../bit_depth_template.c"
-
- void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
- void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
-@@ -43,6 +44,11 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs,
- void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride);
-
-+void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
-+void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
-+void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
-+void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
-+
- #define PUT_PIXELS(name) \
- void name(int16_t *dst, uint8_t *src, \
- ptrdiff_t srcstride, int height, \
-@@ -151,6 +157,44 @@ void ff_hevc_put_qpel_bi_neon_wrapper(uint8_t *dst, ptrdiff_t dststride, uint8_t
- put_hevc_qpel_uw_neon[my][mx](dst, dststride, src, srcstride, width, height, src2, MAX_PB_SIZE);
- }
-
-+static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src,
-+ int16_t *sao_offset_val, int sao_left_class, int width, int height)
-+{
-+ pixel *dst = (pixel *)_dst;
-+ pixel *src = (pixel *)_src;
-+ int8_t offset_table[32] = { 0 };
-+ int k, y, x;
-+ int shift = 3; // BIT_DEPTH - 5
-+
-+ stride_src /= sizeof(pixel);
-+ stride_dst /= sizeof(pixel);
-+
-+ for (k = 0; k < 4; k++)
-+ offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];
-+
-+ switch(width){
-+ case 8:
-+ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ break;
-+ case 16:
-+ ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ break;
-+ case 32:
-+ ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ break;
-+ case 64:
-+ ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ break;
-+ default:
-+ for (y = 0; y < height; y++) {
-+ for (x = 0; x < width; x++)
-+ dst[x] = av_clip_pixel(src[x] + offset_table[src[x] >> shift]);
-+ dst += stride_dst;
-+ src += stride_src;
-+ }
-+ }
-+}
-+
- av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
- {
- if (bit_depth == 8) {
-@@ -170,6 +214,9 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
- c->transform_add[2] = ff_hevc_transform_add_16x16_neon_8;
- c->transform_add[3] = ff_hevc_transform_add_32x32_neon_8;
- c->idct_4x4_luma = ff_hevc_transform_luma_4x4_neon_8;
-+ for (x = 0; x < sizeof c->sao_band_filter / sizeof *c->sao_band_filter; x++) {
-+ c->sao_band_filter[x] = ff_hevc_sao_band_neon_wrapper;
-+ }
- put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8;
- put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8;
- put_hevc_qpel_neon[3][0] = ff_hevc_put_qpel_v3_neon_8;
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-new file mode 100644
-index 0000000..1f0ad64
---- /dev/null
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -0,0 +1,204 @@
-+/*
-+ * Copyright (c) 2014 Seppo Tomperi
-+ *
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#include "libavutil/arm/asm.S"
-+#include "neon.S"
-+
-+function ff_hevc_sao_band_w8_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // offset_table
-+ vpush {d8-d15}
-+ vld1.8 {q0, q1}, [r5] // offset table
-+
-+1: subs r4, #1
-+ vld1.8 {d24}, [r1], r3
-+ vshr.u8 d16, d24, #3
-+ vtbl.8 d16, {q0, q1}, d16
-+ vmovl.s8 q2, d16
-+ vmovl.u8 q6, d24
-+ vadd.s16 q2, q6
-+ vqmovun.s16 d4, q2
-+ vst1.8 {d4}, [r0], r2
-+ bne 1b
-+
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_band_w16_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // offset_table
-+ vpush {d8-d15}
-+ vld1.8 {q0, q1}, [r5] // offset table
-+
-+1: subs r4, #1
-+ vld1.8 {q12}, [r1], r3
-+
-+ vshr.u8 q8, q12, #3
-+
-+ vtbl.8 d16, {q0, q1}, d16
-+ vtbl.8 d17, {q0, q1}, d17
-+
-+ vmovl.s8 q2, d16
-+ vmovl.s8 q3, d17
-+
-+ vmovl.u8 q6, d24
-+ vmovl.u8 q7, d25
-+
-+ vadd.s16 q2, q6
-+ vadd.s16 q3, q7
-+
-+ vqmovun.s16 d4, q2
-+ vqmovun.s16 d5, q3
-+
-+ vstm.8 r0, {q2}
-+ add r0, r2
-+ bne 1b
-+
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_band_w32_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // offset_table
-+ vpush {d8-d15}
-+ vld1.8 {q0, q1}, [r5] // offset table
-+
-+1: subs r4, #1
-+ vld1.8 {q12-q13}, [r1], r3
-+
-+ vshr.u8 q8, q12, #3
-+ vshr.u8 q9, q13, #3
-+
-+ vtbl.8 d16, {q0, q1}, d16
-+ vtbl.8 d17, {q0, q1}, d17
-+ vtbl.8 d18, {q0, q1}, d18
-+ vtbl.8 d19, {q0, q1}, d19
-+
-+ vmovl.s8 q2, d16
-+ vmovl.s8 q3, d17 // q8 free
-+ vmovl.s8 q4, d18
-+ vmovl.s8 q5, d19 // q9 free
-+
-+ vmovl.u8 q6, d24
-+ vmovl.u8 q7, d25 // q12 free
-+ vmovl.u8 q8, d26
-+ vmovl.u8 q9, d27 // q13 free
-+
-+ vadd.s16 q2, q6
-+ vadd.s16 q3, q7
-+ vadd.s16 q4, q8
-+ vadd.s16 q5, q9
-+
-+ vqmovun.s16 d4, q2
-+ vqmovun.s16 d5, q3
-+ vqmovun.s16 d6, q4 // q4 free
-+ vqmovun.s16 d7, q5 // q5 free
-+
-+ vst1.8 {q2-q3}, [r0], r2
-+ bne 1b
-+
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_band_w64_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // offset_table
-+ vpush {d8-d15}
-+ vld1.8 {q0, q1}, [r5] // offset table
-+
-+1: subs r4, #1
-+ vld1.8 {q12-q13}, [r1]!
-+ vld1.8 {q14-q15}, [r1], r3
-+ sub r1, #32
-+
-+ vshr.u8 q8, q12, #3
-+ vshr.u8 q9, q13, #3
-+ vshr.u8 q10, q14, #3
-+ vshr.u8 q11, q15, #3
-+
-+ vtbl.8 d16, {q0, q1}, d16
-+ vtbl.8 d17, {q0, q1}, d17
-+ vtbl.8 d18, {q0, q1}, d18
-+ vtbl.8 d19, {q0, q1}, d19
-+ vtbl.8 d20, {q0, q1}, d20
-+ vtbl.8 d21, {q0, q1}, d21
-+ vtbl.8 d22, {q0, q1}, d22
-+ vtbl.8 d23, {q0, q1}, d23
-+
-+ vmovl.s8 q2, d16
-+ vmovl.s8 q3, d17 // q8 free
-+ vmovl.s8 q4, d18
-+ vmovl.s8 q5, d19 // q9 free
-+
-+ vmovl.u8 q6, d24
-+ vmovl.u8 q7, d25 // q12 free
-+ vmovl.u8 q8, d26
-+ vmovl.u8 q9, d27 // q13 free
-+
-+ vadd.s16 q2, q6
-+ vadd.s16 q3, q7
-+ vadd.s16 q4, q8
-+ vadd.s16 q5, q9
-+
-+ vqmovun.s16 d4, q2
-+ vqmovun.s16 d5, q3
-+ vqmovun.s16 d6, q4 // q4 free
-+ vqmovun.s16 d7, q5 // q5 free
-+
-+ // free q4 -q9, q12 - q13
-+ vmovl.s8 q4, d20
-+ vmovl.s8 q5, d21 // q10 free
-+ vmovl.s8 q6, d22
-+ vmovl.s8 q7, d23 // q11 free
-+
-+ vmovl.u8 q8, d28
-+ vmovl.u8 q9, d29 // q14 free
-+ vmovl.u8 q10, d30
-+ vmovl.u8 q11, d31 // q15 free
-+
-+ vadd.s16 q4, q8
-+ vadd.s16 q5, q9
-+ vadd.s16 q6, q10
-+ vadd.s16 q7, q11
-+
-+ vqmovun.s16 d8, q4
-+ vqmovun.s16 d9, q5
-+ vqmovun.s16 d10, q6
-+ vqmovun.s16 d11, q7
-+
-+ vstm.8 r0, {q2-q5}
-+ add r0, r2
-+ bne 1b
-+
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
---
-2.5.0
-
-
-From 8429b1de64bb871d57651ecfe3b084e2dfe0af51 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Wed, 27 May 2015 18:10:20 +0100
-Subject: [PATCH 2/9] added NEON optimized sao edge for eo1 width 64
-
----
- libavcodec/arm/hevcdsp_init_neon.c | 47 ++++++++++++
- libavcodec/arm/hevcdsp_sao_neon.S | 147 +++++++++++++++++++++++++++++++++++++
- 2 files changed, 194 insertions(+)
-
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index 69e2b2c..c7b5404 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -22,6 +22,7 @@
- #include "libavutil/arm/cpu.h"
- #include "libavcodec/hevcdsp.h"
- #include "hevcdsp_arm.h"
-+#include "libavcodec/avcodec.h"
- #include "../bit_depth_template.c"
-
- void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
-@@ -48,6 +49,7 @@ void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_d
- void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
- void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
- void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
-+void ff_hevc_sao_edge_eo1_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-
- #define PUT_PIXELS(name) \
- void name(int16_t *dst, uint8_t *src, \
-@@ -195,6 +197,50 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
- }
- }
-
-+#define CMP(a, b) ((a) > (b) ? 1 : ((a) == (b) ? 0 : -1))
-+static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t *_src /* align 32 */, ptrdiff_t stride_dst,
-+ int16_t *_sao_offset_val, int eo, int width, int height)
-+{
-+ static const uint8_t edge_idx[] = { 1, 2, 0, 3, 4 };
-+ static const int8_t pos[4][2][2] = {
-+ { { -1, 0 }, { 1, 0 } }, // horizontal
-+ { { 0, -1 }, { 0, 1 } }, // vertical
-+ { { -1, -1 }, { 1, 1 } }, // 45 degree
-+ { { 1, -1 }, { -1, 1 } }, // 135 degree
-+ };
-+ int8_t sao_offset_val[8]; // padding of 3 for vld
-+ ptrdiff_t stride_src = (2*MAX_PB_SIZE + FF_INPUT_BUFFER_PADDING_SIZE);
-+ pixel *dst = (pixel *)_dst;
-+ pixel *src = (pixel *)_src;
-+ int a_stride, b_stride;
-+ int x, y;
-+
-+ for (x = 0; x < 5; x++) {
-+ sao_offset_val[x] = _sao_offset_val[x];
-+ }
-+
-+ stride_src /= sizeof(pixel);
-+ stride_dst /= sizeof(pixel);
-+
-+ if (eo == 1 && width == 64) {
-+ ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ } else {
-+ a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;
-+ b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;
-+ for (y = 0; y < height; y++) {
-+ for (x = 0; x < width; x++) {
-+ int diff0 = CMP(src[x], src[x + a_stride]);
-+ int diff1 = CMP(src[x], src[x + b_stride]);
-+ int offset_val = edge_idx[2 + diff0 + diff1];
-+ dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);
-+ }
-+ src += stride_src;
-+ dst += stride_dst;
-+ }
-+ }
-+}
-+#undef CMP
-+
- av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
- {
- if (bit_depth == 8) {
-@@ -216,6 +262,7 @@ av_cold void ff_hevcdsp_init_neon(HEVCDSPContext *c, const int bit_depth)
- c->idct_4x4_luma = ff_hevc_transform_luma_4x4_neon_8;
- for (x = 0; x < sizeof c->sao_band_filter / sizeof *c->sao_band_filter; x++) {
- c->sao_band_filter[x] = ff_hevc_sao_band_neon_wrapper;
-+ c->sao_edge_filter[x] = ff_hevc_sao_edge_neon_wrapper;
- }
- put_hevc_qpel_neon[1][0] = ff_hevc_put_qpel_v1_neon_8;
- put_hevc_qpel_neon[2][0] = ff_hevc_put_qpel_v2_neon_8;
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index 1f0ad64..5ec2de9 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -202,3 +202,150 @@ function ff_hevc_sao_band_w64_neon_8, export=1
- bx lr
- endfunc
-
-+function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x02
-+ vpush {d8-d15}
-+1: subs r4, #1
-+ // load a
-+ sub r1, r3
-+ vld1.8 {q0-q1}, [r1]!
-+ vld1.8 {q2-q3}, [r1], r3
-+ sub r1, #32
-+ // load c
-+ vld1.8 {q4-q5}, [r1]!
-+ vld1.8 {q6-q7}, [r1], r3
-+ sub r1, #32
-+ // load b
-+ vld1.8 {q8-q9}, [r1]!
-+ vld1.8 {q10-q11}, [r1], r3
-+ sub r1, #32
-+
-+ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
-+ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
-+ vcgt.u8 q13, q5, q1
-+ vcgt.u8 q1, q1, q5
-+ vcgt.u8 q14, q6, q2
-+ vcgt.u8 q2, q2, q6
-+ vcgt.u8 q15, q7, q3
-+ vcgt.u8 q3, q3, q7
-+
-+ vsub.s8 q12, q0, q12 // diff0
-+ vsub.s8 q13, q1, q13
-+ vsub.s8 q14, q2, q14
-+ vsub.s8 q15, q3, q15
-+
-+ vcgt.u8 q0, q4, q8 // c > b
-+ vcgt.u8 q8, q8, q4 // b > c
-+ vcgt.u8 q1, q5, q9
-+ vcgt.u8 q9, q9, q5
-+ vcgt.u8 q2, q6, q10
-+ vcgt.u8 q10, q10, q6
-+ vcgt.u8 q3, q7, q11
-+ vcgt.u8 q11, q11, q7
-+
-+ vsub.s8 q0, q8, q0 // diff1
-+ vsub.s8 q1, q9, q1
-+ vsub.s8 q2, q10, q2
-+ vsub.s8 q3, q11, q3
-+
-+ veor.u8 q8, q8 // zero register
-+ vdup.s8 q9, r6 // 2 to all elements
-+ add r6, #1
-+ vdup.s8 q10, r6 // 3 to all elements
-+ sub r6, #1
-+
-+ vadd.s8 q0, q12 //diff0 + diff1
-+ vadd.s8 q1, q13
-+ vadd.s8 q2, q14
-+ vadd.s8 q3, q15
-+
-+ vcgt.s8 q4, q0, q8 // diff0 + diff1 > 0
-+ vcgt.s8 q5, q1, q8
-+ vcgt.s8 q6, q2, q8
-+ vcgt.s8 q7, q3, q8
-+
-+ vclt.s8 q11, q0, q8 // diff0 + diff1 < 0
-+ vclt.s8 q12, q1, q8
-+ vclt.s8 q13, q2, q8
-+ vclt.s8 q14, q3, q8
-+
-+ vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
-+ vand.8 q15, q8, q4
-+ vadd.s8 q8, q0, q10 // diff0 + diff1 + 3
-+ vand.8 q8, q8, q11
-+ vadd.s8 q0, q15, q8 // offset_idx
-+
-+ vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
-+ vand.8 q15, q8, q5
-+ vadd.s8 q8, q1, q10 // diff0 + diff1 + 3
-+ vand.8 q8, q8, q12
-+ vadd.s8 q1, q15, q8 // offset_idx
-+
-+ vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 + 2
-+ vand.8 q15, q8, q6
-+ vadd.s8 q8, q2, q10 // diff0 + diff1 + 2 + 3
-+ vand.8 q8, q8, q13
-+ vadd.s8 q2, q15, q8 // offset_idx
-+
-+ vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 + 2
-+ vand.8 q15, q8, q7
-+ vadd.s8 q8, q3, q10 // diff0 + diff1 + 2 + 3
-+ vand.8 q8, q8, q14
-+ vadd.s8 q3, q15, q8 // offset_idx
-+ // TODO: load only once
-+ vld1.8 d16, [r5]
-+
-+ vtbl.8 d0, {d16}, d0
-+ vtbl.8 d1, {d16}, d1
-+ vtbl.8 d2, {d16}, d2
-+ vtbl.8 d3, {d16}, d3
-+ vtbl.8 d4, {d16}, d4
-+ vtbl.8 d5, {d16}, d5
-+ vtbl.8 d6, {d16}, d6
-+ vtbl.8 d7, {d16}, d7
-+
-+ // TODO: load only once
-+ // load c again
-+ sub r1, r3
-+ sub r1, r3
-+ vld1.8 {q4-q5}, [r1]!
-+ vld1.8 {q6-q7}, [r1], r3
-+ sub r1, #32
-+
-+ vmovl.u8 q8, d8
-+ vmovl.u8 q9, d9
-+ vmovl.u8 q10, d10
-+ vmovl.u8 q11, d11
-+ vmovl.u8 q12, d12
-+ vmovl.u8 q13, d13
-+ vmovl.u8 q14, d14
-+ vmovl.u8 q15, d15
-+
-+ vaddw.s8 q8, d0
-+ vaddw.s8 q9, d1
-+ vaddw.s8 q10, d2
-+ vaddw.s8 q11, d3
-+ vaddw.s8 q12, d4
-+ vaddw.s8 q13, d5
-+ vaddw.s8 q14, d6
-+ vaddw.s8 q15, d7
-+
-+ vqmovun.s16 d0, q8
-+ vqmovun.s16 d1, q9
-+ vqmovun.s16 d2, q10
-+ vqmovun.s16 d3, q11
-+ vqmovun.s16 d4, q12
-+ vqmovun.s16 d5, q13
-+ vqmovun.s16 d6, q14
-+ vqmovun.s16 d7, q15
-+
-+ vstm r0, {q0-q3}
-+ add r0, r2
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
---
-2.5.0
-
-
-From 402e2bd1c5ad659c757bf9734abe6331904fb9e2 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Tue, 16 Dec 2014 16:28:25 +0200
-Subject: [PATCH 3/9] Added SAO edge offset for ARM NEON w32 and w64
-
----
- libavcodec/arm/hevcdsp_init_neon.c | 46 +++-
- libavcodec/arm/hevcdsp_sao_neon.S | 510 +++++++++++++++++++++++++++++++------
- 2 files changed, 474 insertions(+), 82 deletions(-)
-
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index c7b5404..c32940e 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -49,7 +49,16 @@ void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_d
- void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
- void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
- void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
-+
-+void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-+void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-+void ff_hevc_sao_edge_eo2_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-+void ff_hevc_sao_edge_eo3_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-+
-+void ff_hevc_sao_edge_eo0_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
- void ff_hevc_sao_edge_eo1_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-+void ff_hevc_sao_edge_eo2_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-+void ff_hevc_sao_edge_eo3_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-
- #define PUT_PIXELS(name) \
- void name(int16_t *dst, uint8_t *src, \
-@@ -222,9 +231,40 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
- stride_src /= sizeof(pixel);
- stride_dst /= sizeof(pixel);
-
-- if (eo == 1 && width == 64) {
-- ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-- } else {
-+ switch (width) {
-+ case 32:
-+ switch(eo) {
-+ case 0:
-+ ff_hevc_sao_edge_eo0_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ case 1:
-+ ff_hevc_sao_edge_eo1_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ case 2:
-+ ff_hevc_sao_edge_eo2_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ case 3:
-+ ff_hevc_sao_edge_eo3_w32_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ }
-+ break;
-+ case 64:
-+ switch(eo) {
-+ case 0:
-+ ff_hevc_sao_edge_eo0_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ case 1:
-+ ff_hevc_sao_edge_eo1_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ case 2:
-+ ff_hevc_sao_edge_eo2_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ case 3:
-+ ff_hevc_sao_edge_eo3_w64_neon_8(dst, src, stride_dst, stride_src, height, sao_offset_val);
-+ break;
-+ }
-+ break;
-+ default:
- a_stride = pos[eo][0][0] + pos[eo][0][1] * stride_src;
- b_stride = pos[eo][1][0] + pos[eo][1][1] * stride_src;
- for (y = 0; y < height; y++) {
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index 5ec2de9..4687012 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -202,27 +202,7 @@ function ff_hevc_sao_band_w64_neon_8, export=1
- bx lr
- endfunc
-
--function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x02
-- vpush {d8-d15}
--1: subs r4, #1
-- // load a
-- sub r1, r3
-- vld1.8 {q0-q1}, [r1]!
-- vld1.8 {q2-q3}, [r1], r3
-- sub r1, #32
-- // load c
-- vld1.8 {q4-q5}, [r1]!
-- vld1.8 {q6-q7}, [r1], r3
-- sub r1, #32
-- // load b
-- vld1.8 {q8-q9}, [r1]!
-- vld1.8 {q10-q11}, [r1], r3
-- sub r1, #32
--
-+.macro edge_w64_body
- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
- vcgt.u8 q13, q5, q1
-@@ -251,69 +231,61 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
- vsub.s8 q2, q10, q2
- vsub.s8 q3, q11, q3
-
-- veor.u8 q8, q8 // zero register
-- vdup.s8 q9, r6 // 2 to all elements
-- add r6, #1
-- vdup.s8 q10, r6 // 3 to all elements
-- sub r6, #1
--
- vadd.s8 q0, q12 //diff0 + diff1
- vadd.s8 q1, q13
- vadd.s8 q2, q14
- vadd.s8 q3, q15
-
-- vcgt.s8 q4, q0, q8 // diff0 + diff1 > 0
-- vcgt.s8 q5, q1, q8
-- vcgt.s8 q6, q2, q8
-- vcgt.s8 q7, q3, q8
--
-- vclt.s8 q11, q0, q8 // diff0 + diff1 < 0
-- vclt.s8 q12, q1, q8
-- vclt.s8 q13, q2, q8
-- vclt.s8 q14, q3, q8
--
-- vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
-- vand.8 q15, q8, q4
-- vadd.s8 q8, q0, q10 // diff0 + diff1 + 3
-- vand.8 q8, q8, q11
-- vadd.s8 q0, q15, q8 // offset_idx
--
-- vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
-- vand.8 q15, q8, q5
-- vadd.s8 q8, q1, q10 // diff0 + diff1 + 3
-- vand.8 q8, q8, q12
-- vadd.s8 q1, q15, q8 // offset_idx
--
-- vadd.s8 q8, q2, q9 // diff0 + diff1 + 2 + 2
-- vand.8 q15, q8, q6
-- vadd.s8 q8, q2, q10 // diff0 + diff1 + 2 + 3
-- vand.8 q8, q8, q13
-- vadd.s8 q2, q15, q8 // offset_idx
--
-- vadd.s8 q8, q3, q9 // diff0 + diff1 + 2 + 2
-- vand.8 q15, q8, q7
-- vadd.s8 q8, q3, q10 // diff0 + diff1 + 2 + 3
-- vand.8 q8, q8, q14
-- vadd.s8 q3, q15, q8 // offset_idx
-- // TODO: load only once
-- vld1.8 d16, [r5]
--
-- vtbl.8 d0, {d16}, d0
-- vtbl.8 d1, {d16}, d1
-- vtbl.8 d2, {d16}, d2
-- vtbl.8 d3, {d16}, d3
-- vtbl.8 d4, {d16}, d4
-- vtbl.8 d5, {d16}, d5
-- vtbl.8 d6, {d16}, d6
-- vtbl.8 d7, {d16}, d7
--
-- // TODO: load only once
-- // load c again
-- sub r1, r3
-- sub r1, r3
-- vld1.8 {q4-q5}, [r1]!
-- vld1.8 {q6-q7}, [r1], r3
-- sub r1, #32
-+ vdup.s8 q9, r6 // 3 to all elements
-+ sub r6, #1
-+
-+ vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
-+ vclt.s8 q13, q1, #0
-+ vclt.s8 q14, q2, #0
-+ vclt.s8 q15, q3, #0
-+
-+ vadd.s8 q8, q0, q9 // diff0 + diff1 + 3
-+ vadd.s8 q10, q1, q9
-+ vand.8 q12, q8, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
-+ vand.8 q13, q10, q13
-+ vadd.s8 q8, q2, q9
-+ vadd.s8 q10, q3, q9
-+ vand.8 q14, q8, q14
-+ vand.8 q15, q10, q15
-+
-+ vdup.s8 q9, r6 // 2 to all elements
-+ add r6, #1
-+
-+ vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
-+ vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
-+ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-+ vcgt.s8 q10, q1, #0
-+ vadd.s8 q0, q11, q12 // offset_idx
-+
-+ vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
-+ vcgt.s8 q12, q2, #0
-+ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-+ vadd.s8 q8, q2, q9 // diff0 + diff1 + 2
-+ vadd.s8 q1, q11, q13
-+
-+ vand.8 q11, q8, q12 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-+ vcgt.s8 q10, q3, #0
-+ vadd.s8 q2, q11, q14
-+
-+ vadd.s8 q8, q3, q9 // diff0 + diff1 + 2
-+ vmov.32 d18[0], r7 // load offset table from general registers
-+ vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-+ vmov.32 d18[1], r5 // load rest of offset table
-+ vadd.s8 q3, q11, q15
-+
-+ vtbl.8 d0, {d18}, d0
-+ vtbl.8 d1, {d18}, d1
-+ vtbl.8 d2, {d18}, d2
-+ vtbl.8 d3, {d18}, d3
-+ vtbl.8 d4, {d18}, d4
-+ vtbl.8 d5, {d18}, d5
-+ vtbl.8 d6, {d18}, d6
-+ vtbl.8 d7, {d18}, d7
-
- vmovl.u8 q8, d8
- vmovl.u8 q9, d9
-@@ -344,8 +316,388 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
-
- vstm r0, {q0-q3}
- add r0, r2
-+.endm
-+
-+.macro edge_w32_body
-+ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
-+ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
-+ vcgt.u8 q13, q5, q1
-+ vcgt.u8 q1, q1, q5
-+
-+ vsub.s8 q12, q0, q12 // diff0
-+ vcgt.u8 q0, q4, q8 // c > b
-+ vsub.s8 q13, q1, q13 // diff0 part 2
-+
-+ vcgt.u8 q6, q8, q4 // b > c
-+ vcgt.u8 q1, q5, q9
-+ vcgt.u8 q7, q9, q5
-+
-+ vsub.s8 q0, q6, q0 // diff1
-+ vsub.s8 q1, q7, q1 // diff1 part 2
-+ vadd.s8 q0, q12 //diff0 + diff1
-+
-+ vdup.s8 q7, r6 // 3 to all elements
-+ sub r6, #1
-+ vadd.s8 q1, q13
-+
-+ vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
-+ vclt.s8 q13, q1, #0
-+
-+ vadd.s8 q6, q0, q7 // diff0 + diff1 + 3
-+ vadd.s8 q10, q1, q7
-+ vdup.s8 q7, r6 // 2 to all elements
-+ add r6, #1
-+ vand.8 q12, q6, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
-+ vand.8 q13, q10, q13
-+
-+
-+ vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
-+ vadd.s8 q6, q0, q7 // diff0 + diff1 + 2
-+ vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-+ vcgt.s8 q10, q1, #0
-+ vadd.s8 q0, q11, q12 // offset_idx
-+
-+ vadd.s8 q6, q1, q7 // diff0 + diff1 + 2
-+ vmov.32 d14[0], r7 // load offset table from general registers
-+ vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-+ vmov.32 d14[1], r5 // load rest of offset table
-+ vadd.s8 q1, q11, q13
-+
-+ vtbl.8 d0, {d14}, d0
-+ vtbl.8 d1, {d14}, d1
-+ vtbl.8 d2, {d14}, d2
-+ vtbl.8 d3, {d14}, d3
-+
-+ vmovl.u8 q6, d8
-+ vmovl.u8 q7, d9
-+ vmovl.u8 q10, d10
-+ vmovl.u8 q11, d11
-+
-+ vaddw.s8 q6, d0
-+ vaddw.s8 q7, d1
-+ vaddw.s8 q10, d2
-+ vaddw.s8 q11, d3
-+
-+ vqmovun.s16 d0, q6
-+ vqmovun.s16 d1, q7
-+ vqmovun.s16 d2, q10
-+ vqmovun.s16 d3, q11
-+
-+ vstm r0, {q0-q1}
-+ add r0, r2
-+.endm
-+
-+function ff_hevc_sao_edge_eo0_w64_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ ldr r5, [r5]
-+ vpush {d8-d15}
-+ sub r1, #8
-+1: subs r4, #1
-+ vld1.64 {q10-q11}, [r1]!
-+ vld1.64 {q12-q13}, [r1]!
-+ vld1.64 {q14}, [r1], r3
-+ sub r1, #64
-+ // load a
-+ vext.8 q0, q10, q11, #7
-+ vext.8 q1, q11, q12, #7
-+ vext.8 q2, q12, q13, #7
-+ vext.8 q3, q13, q14, #7
-+ // load c
-+ vext.8 q4, q10, q11, #8
-+ vext.8 q5, q11, q12, #8
-+ vext.8 q6, q12, q13, #8
-+ vext.8 q7, q13, q14, #8
-+ // load b
-+ vext.8 q8, q10, q11, #9
-+ vext.8 q9, q11, q12, #9
-+ vext.8 q10, q12, q13, #9
-+ vext.8 q11, q13, q14, #9
-+ edge_w64_body
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ ldr r5, [r5]
-+ vpush {d8-d15}
-+ sub r1, r3
-+ // load a
-+ vld1.8 {q0-q1}, [r1]!
-+ vld1.8 {q2-q3}, [r1], r3
-+ sub r1, #32
-+1: subs r4, #1
-+ // load c
-+ vld1.8 {q4-q5}, [r1]!
-+ vld1.8 {q6-q7}, [r1], r3
-+ sub r1, #32
-+ // load b
-+ vld1.8 {q8-q9}, [r1]!
-+ vld1.8 {q10-q11}, [r1]
-+ sub r1, #32
-+ edge_w64_body
-+ // copy c to a
-+ vmov.64 q0, q4
-+ vmov.64 q1, q5
-+ vmov.64 q2, q6
-+ vmov.64 q3, q7
- bne 1b
- vpop {d8-d15}
- pop {r4-r8}
- bx lr
- endfunc
-+
-+function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ ldr r5, [r5]
-+ vpush {d8-d15}
-+1: sub r1, r3
-+ // load a
-+ // TODO: fix unaligned load
-+ // don't reload a like in eo1
-+ sub r1, #1
-+ vld1.8 {q0-q1}, [r1]!
-+ vld1.8 {q2-q3}, [r1], r3
-+ sub r1, #31
-+ subs r4, #1
-+ // load c
-+ vld1.8 {q4-q5}, [r1]!
-+ vld1.8 {q6-q7}, [r1], r3
-+ sub r1, #32
-+ // load b
-+ add r1, #1
-+ vld1.8 {q8-q9}, [r1]!
-+ vld1.8 {q10-q11}, [r1]
-+ sub r1, #33
-+ edge_w64_body
-+ // copy c to a
-+ vmov.64 q0, q4
-+ vmov.64 q1, q5
-+ vmov.64 q2, q6
-+ vmov.64 q3, q7
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ ldr r5, [r5]
-+ vpush {d8-d15}
-+1: sub r1, r3
-+ // load a
-+ // TODO: fix unaligned load
-+ // don't reload a like in eo1
-+ add r1, #1
-+ vld1.8 {q0-q1}, [r1]!
-+ vld1.8 {q2-q3}, [r1], r3
-+ sub r1, #33
-+ subs r4, #1
-+ // load c
-+ vld1.8 {q4-q5}, [r1]!
-+ vld1.8 {q6-q7}, [r1], r3
-+ sub r1, #32
-+ // load b
-+ sub r1, #1
-+ vld1.8 {q8-q9}, [r1]!
-+ vld1.8 {q10-q11}, [r1]
-+ sub r1, #31
-+ edge_w64_body
-+ // copy c to a
-+ vmov.64 q0, q4
-+ vmov.64 q1, q5
-+ vmov.64 q2, q6
-+ vmov.64 q3, q7
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_edge_eo0_w32_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ ldr r5, [r5]
-+ vpush {d8-d15}
-+ sub r1, #8 // load 8 extra bytes
-+1: subs r4, #1
-+ vld1.8 {q10-q11}, [r1]
-+ add r1, #32
-+ vld1.8 {q12}, [r1], r3 // only first 9 bytes are used
-+ sub r1, #32
-+ // a
-+ vext.8 q0, q10, q11, #7
-+ vext.8 q1, q11, q12, #7
-+ // c
-+ vext.8 q4, q10, q11, #8
-+ vext.8 q5, q11, q12, #8
-+ // b
-+ vext.8 q8, q10, q11, #9
-+ vext.8 q9, q11, q12, #9
-+ edge_w32_body
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_edge_eo1_w32_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ ldr r5, [r5]
-+ vpush {d8-d15}
-+ // load a
-+ sub r1, r3
-+ vld1.8 {q0-q1}, [r1], r3
-+ // load c
-+ vld1.8 {q4-q5}, [r1], r3
-+1: subs r4, #1
-+ // load b
-+ vld1.8 {q8-q9}, [r1], r3
-+ edge_w32_body
-+ // inputs for next loop iteration
-+ // a
-+ vmov.64 q0, q4
-+ vmov.64 q1, q5
-+ // c
-+ vmov.64 q4, q8
-+ vmov.64 q5, q9
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_edge_eo2_w32_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ ldr r5, [r5]
-+ vpush {d8-d15}
-+ // load a
-+ sub r1, r3
-+ sub r1, #8
-+ vld1.8 {q10-q11}, [r1]
-+ add r1, #32
-+ vld1.8 {q12}, [r1], r3
-+ sub r1, #32
-+ vext.8 q0, q10, q11, #7
-+ vext.8 q1, q11, q12, #7
-+ // load c
-+ vld1.8 {q10-q11}, [r1]
-+ add r1, #32
-+ vld1.8 {q12}, [r1], r3
-+ sub r1, #32
-+ vext.8 q4, q10, q11, #8
-+ vext.8 q5, q11, q12, #8
-+ vext.8 q2, q10, q11, #7
-+1: subs r4, #1
-+ // load b
-+ vld1.8 {q10-q11}, [r1]
-+ add r1, #32
-+ vld1.8 {q12}, [r1], r3
-+ sub r1, #32
-+ vext.8 q8, q10, q11, #9
-+ vext.8 q9, q11, q12, #9
-+ vext.8 q14, q10, q11, #8
-+ vext.8 q15, q11, q12, #8
-+ vext.8 q3, q10, q11, #7
-+ edge_w32_body
-+ // inputs for next loop iteration
-+ // a
-+ vmov.8 q0, q2
-+ vext.8 q1, q4, q5, #15
-+ // c
-+ vmov.8 q4, q14
-+ vmov.8 q5, q15
-+ vmov.8 q2, q3
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_edge_eo3_w32_neon_8, export=1
-+ push {r4-r8}
-+ ldr r4, [sp, #20] // height
-+ ldr r5, [sp, #24] // sao_offset_val_table
-+ ldr r6, =0x03
-+ ldr r7, [r5]
-+ add r5, #4
-+ sub r1, r3
-+ ldr r5, [r5]
-+ sub r1, #8
-+ vpush {d8-d15}
-+ // load a
-+ vld1.8 {q10-q11}, [r1]
-+ add r1, #32
-+ vld1.8 {q12}, [r1], r3
-+ sub r1, #32
-+ vext.8 q0, q10, q11, #9
-+ vext.8 q1, q11, q12, #9
-+ // load c
-+ vld1.8 {q10-q11}, [r1]
-+ add r1, #32
-+ vld1.8 {q12}, [r1], r3
-+ sub r1, #32
-+ vext.8 q4, q10, q11, #8
-+ vext.8 q5, q11, q12, #8
-+ vext.8 q2, q12, q11, #8
-+1: subs r4, #1
-+ // load b
-+ vld1.8 {q10-q11}, [r1]
-+ add r1, #32
-+ vld1.8 {q12}, [r1], r3
-+ sub r1, #32
-+ vext.8 q8, q10, q11, #7
-+ vext.8 q9, q11, q12, #7
-+ vext.8 q3, q12, q10, #7
-+ edge_w32_body
-+ // inputs for next loop iteration
-+ // a
-+ vext.8 q0, q4, q5, #1
-+ vext.8 q1, q5, q2, #1
-+ // c
-+ vext.8 q4, q8, q9, #1
-+ vext.8 q5, q9, q3, #1
-+ vext.8 q2, q3, q1, #1
-+ bne 1b
-+ vpop {d8-d15}
-+ pop {r4-r8}
-+ bx lr
-+endfunc
-+
---
-2.5.0
-
-
-From 1898d052a73370166d57e17cc7c52b7275887df3 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Fri, 19 Dec 2014 09:44:10 +0200
-Subject: [PATCH 4/9] Improved SAO band NEON opimizations made SAO buffer 16
- byte aligned added alignment hints to loads and stores optimized register
- usage in SAO band neon assembly
-
----
- libavcodec/arm/hevcdsp_sao_neon.S | 212 +++++++++++++++-----------------------
- 1 file changed, 82 insertions(+), 130 deletions(-)
-
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index 4687012..ac21013 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -22,120 +22,84 @@
- #include "neon.S"
-
- function ff_hevc_sao_band_w8_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // offset_table
-- vpush {d8-d15}
-- vld1.8 {q0, q1}, [r5] // offset table
-+ ldr r12, [sp, #4] // offset_table address
-+ vld1.8 {q0, q1}, [r12] // offset table
-+ ldr r12, [sp, #0] // height
-
--1: subs r4, #1
-- vld1.8 {d24}, [r1], r3
-+1: subs r12, #1
-+ vld1.8 {d24}, [r1,:64], r3
- vshr.u8 d16, d24, #3
- vtbl.8 d16, {q0, q1}, d16
-- vmovl.s8 q2, d16
- vmovl.u8 q6, d24
-- vadd.s16 q2, q6
-+ vaddw.s8 q6, d16
- vqmovun.s16 d4, q2
-- vst1.8 {d4}, [r0], r2
-+ vst1.8 {d4}, [r0,:64], r2
- bne 1b
-
-- vpop {d8-d15}
-- pop {r4-r8}
- bx lr
- endfunc
-
- function ff_hevc_sao_band_w16_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // offset_table
-- vpush {d8-d15}
-- vld1.8 {q0, q1}, [r5] // offset table
--
--1: subs r4, #1
-- vld1.8 {q12}, [r1], r3
-+ ldr r12, [sp, #4] // offset_table address
-+ vld1.8 {q0, q1}, [r12] // offset table
-+ ldr r12, [sp, #0] // height
-
-+1: subs r12, #1
-+ vld1.8 {q12}, [r1,:128], r3
- vshr.u8 q8, q12, #3
--
- vtbl.8 d16, {q0, q1}, d16
- vtbl.8 d17, {q0, q1}, d17
--
-- vmovl.s8 q2, d16
-- vmovl.s8 q3, d17
--
-- vmovl.u8 q6, d24
-- vmovl.u8 q7, d25
--
-- vadd.s16 q2, q6
-- vadd.s16 q3, q7
--
-- vqmovun.s16 d4, q2
-- vqmovun.s16 d5, q3
--
-- vstm.8 r0, {q2}
-- add r0, r2
-+ vmovl.u8 q10, d24
-+ vmovl.u8 q11, d25
-+ vaddw.s8 q10, d16
-+ vaddw.s8 q11, d17
-+ vqmovun.s16 d4, q10
-+ vqmovun.s16 d5, q11
-+ vst1.8 {q2}, [r0,:128], r2
- bne 1b
-
-- vpop {d8-d15}
-- pop {r4-r8}
- bx lr
- endfunc
-
- function ff_hevc_sao_band_w32_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // offset_table
-- vpush {d8-d15}
-- vld1.8 {q0, q1}, [r5] // offset table
--
--1: subs r4, #1
-- vld1.8 {q12-q13}, [r1], r3
--
-- vshr.u8 q8, q12, #3
-- vshr.u8 q9, q13, #3
--
-- vtbl.8 d16, {q0, q1}, d16
-- vtbl.8 d17, {q0, q1}, d17
-- vtbl.8 d18, {q0, q1}, d18
-- vtbl.8 d19, {q0, q1}, d19
--
-- vmovl.s8 q2, d16
-- vmovl.s8 q3, d17 // q8 free
-- vmovl.s8 q4, d18
-- vmovl.s8 q5, d19 // q9 free
--
-- vmovl.u8 q6, d24
-- vmovl.u8 q7, d25 // q12 free
-- vmovl.u8 q8, d26
-- vmovl.u8 q9, d27 // q13 free
--
-- vadd.s16 q2, q6
-- vadd.s16 q3, q7
-- vadd.s16 q4, q8
-- vadd.s16 q5, q9
--
-- vqmovun.s16 d4, q2
-- vqmovun.s16 d5, q3
-- vqmovun.s16 d6, q4 // q4 free
-- vqmovun.s16 d7, q5 // q5 free
--
-- vst1.8 {q2-q3}, [r0], r2
-- bne 1b
--
-- vpop {d8-d15}
-- pop {r4-r8}
-- bx lr
-+ ldr r12, [sp, #4] // offset_table address
-+ vld1.8 {q0, q1}, [r12] // offset table
-+ ldr r12, [sp, #0] // height
-+
-+1: subs r12, #1
-+ vld1.8 {q2-q3}, [r1,:128], r3
-+ vshr.u8 q8, q2, #3
-+ vshr.u8 q9, q3, #3
-+ vtbl.8 d16, {q0, q1}, d16
-+ vtbl.8 d17, {q0, q1}, d17
-+ vtbl.8 d18, {q0, q1}, d18
-+ vtbl.8 d19, {q0, q1}, d19
-+ vmovl.u8 q12, d4
-+ vmovl.u8 q13, d5
-+ vmovl.u8 q14, d6
-+ vmovl.u8 q15, d7
-+ vaddw.s8 q12, d16
-+ vaddw.s8 q13, d17
-+ vaddw.s8 q14, d18
-+ vaddw.s8 q15, d19
-+ vqmovun.s16 d4, q12
-+ vqmovun.s16 d5, q13
-+ vqmovun.s16 d6, q14
-+ vqmovun.s16 d7, q15
-+ vst1.8 {q2-q3}, [r0,:128], r2
-+ bne 1b
-+
-+ bx lr
- endfunc
-
- function ff_hevc_sao_band_w64_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // offset_table
-- vpush {d8-d15}
-- vld1.8 {q0, q1}, [r5] // offset table
-+ ldr r12, [sp, #4] // offset_table address
-+ vld1.8 {q0, q1}, [r12] // offset table
-+ ldr r12, [sp, #0] // height
-
--1: subs r4, #1
-- vld1.8 {q12-q13}, [r1]!
-- vld1.8 {q14-q15}, [r1], r3
-+1: subs r12, #1
-+ vld1.8 {q12-q13}, [r1,:128]!
-+ vld1.8 {q14-q15}, [r1,:128], r3
- sub r1, #32
-
- vshr.u8 q8, q12, #3
-@@ -152,53 +116,41 @@ function ff_hevc_sao_band_w64_neon_8, export=1
- vtbl.8 d22, {q0, q1}, d22
- vtbl.8 d23, {q0, q1}, d23
-
-- vmovl.s8 q2, d16
-- vmovl.s8 q3, d17 // q8 free
-- vmovl.s8 q4, d18
-- vmovl.s8 q5, d19 // q9 free
-+ vmovl.u8 q2, d24
-+ vmovl.u8 q3, d25
-+ vmovl.u8 q12, d26
-+ vmovl.u8 q13, d27
-
-- vmovl.u8 q6, d24
-- vmovl.u8 q7, d25 // q12 free
-- vmovl.u8 q8, d26
-- vmovl.u8 q9, d27 // q13 free
--
-- vadd.s16 q2, q6
-- vadd.s16 q3, q7
-- vadd.s16 q4, q8
-- vadd.s16 q5, q9
-+ vaddw.s8 q2, d16
-+ vaddw.s8 q3, d17
-+ vaddw.s8 q12, d18
-+ vaddw.s8 q13, d19
-
- vqmovun.s16 d4, q2
- vqmovun.s16 d5, q3
-- vqmovun.s16 d6, q4 // q4 free
-- vqmovun.s16 d7, q5 // q5 free
--
-- // free q4 -q9, q12 - q13
-- vmovl.s8 q4, d20
-- vmovl.s8 q5, d21 // q10 free
-- vmovl.s8 q6, d22
-- vmovl.s8 q7, d23 // q11 free
--
-- vmovl.u8 q8, d28
-- vmovl.u8 q9, d29 // q14 free
-- vmovl.u8 q10, d30
-- vmovl.u8 q11, d31 // q15 free
--
-- vadd.s16 q4, q8
-- vadd.s16 q5, q9
-- vadd.s16 q6, q10
-- vadd.s16 q7, q11
--
-- vqmovun.s16 d8, q4
-- vqmovun.s16 d9, q5
-- vqmovun.s16 d10, q6
-- vqmovun.s16 d11, q7
--
-- vstm.8 r0, {q2-q5}
-- add r0, r2
-+ vqmovun.s16 d6, q12
-+ vqmovun.s16 d7, q13
-+
-+ vmovl.u8 q12, d28
-+ vmovl.u8 q13, d29
-+ vmovl.u8 q14, d30
-+ vmovl.u8 q15, d31
-+
-+ vaddw.s8 q12, d20
-+ vaddw.s8 q13, d21
-+ vaddw.s8 q14, d22
-+ vaddw.s8 q15, d23
-+
-+ vqmovun.s16 d8, q12
-+ vqmovun.s16 d9, q13
-+ vqmovun.s16 d10, q14
-+ vqmovun.s16 d11, q15
-+
-+ vst1.8 {q2-q3}, [r0,:128]!
-+ vst1.8 {q4-q5}, [r0,:128], r2
-+ sub r0, #32
- bne 1b
-
-- vpop {d8-d15}
-- pop {r4-r8}
- bx lr
- endfunc
-
---
-2.5.0
-
-
-From 26bd536800db2f50ff6a021e1fda0d0394d1ea01 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Mon, 29 Dec 2014 15:00:49 +0200
-Subject: [PATCH 5/9] better code reuse in NEON SAO band
-
----
- libavcodec/arm/hevcdsp_init_neon.c | 16 ++--
- libavcodec/arm/hevcdsp_sao_neon.S | 155 +++++++++++++------------------------
- 2 files changed, 61 insertions(+), 110 deletions(-)
-
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index c32940e..6379810 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -45,10 +45,10 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs,
- void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride);
-
--void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
--void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
--void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
--void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t * offset_table);
-+void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
-+void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
-+void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
-+void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
-
- void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
- void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-@@ -185,16 +185,16 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
-
- switch(width){
- case 8:
-- ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
- break;
- case 16:
-- ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
- break;
- case 32:
-- ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
- break;
- case 64:
-- ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, height, offset_table);
-+ ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
- break;
- default:
- for (y = 0; y < height; y++) {
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index ac21013..8852550 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -21,53 +21,13 @@
- #include "libavutil/arm/asm.S"
- #include "neon.S"
-
--function ff_hevc_sao_band_w8_neon_8, export=1
-- ldr r12, [sp, #4] // offset_table address
-+.macro init_sao_band
-+ ldr r12, [sp, #0] // offset_table address
- vld1.8 {q0, q1}, [r12] // offset table
-- ldr r12, [sp, #0] // height
--
--1: subs r12, #1
-- vld1.8 {d24}, [r1,:64], r3
-- vshr.u8 d16, d24, #3
-- vtbl.8 d16, {q0, q1}, d16
-- vmovl.u8 q6, d24
-- vaddw.s8 q6, d16
-- vqmovun.s16 d4, q2
-- vst1.8 {d4}, [r0,:64], r2
-- bne 1b
--
-- bx lr
--endfunc
--
--function ff_hevc_sao_band_w16_neon_8, export=1
-- ldr r12, [sp, #4] // offset_table address
-- vld1.8 {q0, q1}, [r12] // offset table
-- ldr r12, [sp, #0] // height
--
--1: subs r12, #1
-- vld1.8 {q12}, [r1,:128], r3
-- vshr.u8 q8, q12, #3
-- vtbl.8 d16, {q0, q1}, d16
-- vtbl.8 d17, {q0, q1}, d17
-- vmovl.u8 q10, d24
-- vmovl.u8 q11, d25
-- vaddw.s8 q10, d16
-- vaddw.s8 q11, d17
-- vqmovun.s16 d4, q10
-- vqmovun.s16 d5, q11
-- vst1.8 {q2}, [r0,:128], r2
-- bne 1b
--
-- bx lr
--endfunc
--
--function ff_hevc_sao_band_w32_neon_8, export=1
-- ldr r12, [sp, #4] // offset_table address
-- vld1.8 {q0, q1}, [r12] // offset table
-- ldr r12, [sp, #0] // height
-+ ldr r12, [sp, #4] // height
-+.endm
-
--1: subs r12, #1
-- vld1.8 {q2-q3}, [r1,:128], r3
-+.macro sao_band_32
- vshr.u8 q8, q2, #3
- vshr.u8 q9, q3, #3
- vtbl.8 d16, {q0, q1}, d16
-@@ -86,6 +46,43 @@ function ff_hevc_sao_band_w32_neon_8, export=1
- vqmovun.s16 d5, q13
- vqmovun.s16 d6, q14
- vqmovun.s16 d7, q15
-+.endm
-+
-+function ff_hevc_sao_band_w8_neon_8, export=1
-+ init_sao_band
-+1: subs r12, #4
-+ vld1.8 {d4}, [r1,:64], r3
-+ vld1.8 {d5}, [r1,:64], r3
-+ vld1.8 {d6}, [r1,:64], r3
-+ vld1.8 {d7}, [r1,:64], r3
-+ sao_band_32
-+ vst1.8 {d4}, [r0,:64], r2
-+ vst1.8 {d5}, [r0,:64], r2
-+ vst1.8 {d6}, [r0,:64], r2
-+ vst1.8 {d7}, [r0,:64], r2
-+ bne 1b
-+
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_band_w16_neon_8, export=1
-+ init_sao_band
-+1: subs r12, #2
-+ vld1.8 {q2}, [r1,:128], r3
-+ vld1.8 {q3}, [r1,:128], r3
-+ sao_band_32
-+ vst1.8 {q2}, [r0,:128], r2
-+ vst1.8 {q3}, [r0,:128], r2
-+ bne 1b
-+
-+ bx lr
-+endfunc
-+
-+function ff_hevc_sao_band_w32_neon_8, export=1
-+ init_sao_band
-+1: subs r12, #1
-+ vld1.8 {q2-q3}, [r1,:128], r3
-+ sao_band_32
- vst1.8 {q2-q3}, [r0,:128], r2
- bne 1b
-
-@@ -93,63 +90,17 @@ function ff_hevc_sao_band_w32_neon_8, export=1
- endfunc
-
- function ff_hevc_sao_band_w64_neon_8, export=1
-- ldr r12, [sp, #4] // offset_table address
-- vld1.8 {q0, q1}, [r12] // offset table
-- ldr r12, [sp, #0] // height
--
--1: subs r12, #1
-- vld1.8 {q12-q13}, [r1,:128]!
-- vld1.8 {q14-q15}, [r1,:128], r3
-- sub r1, #32
--
-- vshr.u8 q8, q12, #3
-- vshr.u8 q9, q13, #3
-- vshr.u8 q10, q14, #3
-- vshr.u8 q11, q15, #3
--
-- vtbl.8 d16, {q0, q1}, d16
-- vtbl.8 d17, {q0, q1}, d17
-- vtbl.8 d18, {q0, q1}, d18
-- vtbl.8 d19, {q0, q1}, d19
-- vtbl.8 d20, {q0, q1}, d20
-- vtbl.8 d21, {q0, q1}, d21
-- vtbl.8 d22, {q0, q1}, d22
-- vtbl.8 d23, {q0, q1}, d23
--
-- vmovl.u8 q2, d24
-- vmovl.u8 q3, d25
-- vmovl.u8 q12, d26
-- vmovl.u8 q13, d27
--
-- vaddw.s8 q2, d16
-- vaddw.s8 q3, d17
-- vaddw.s8 q12, d18
-- vaddw.s8 q13, d19
--
-- vqmovun.s16 d4, q2
-- vqmovun.s16 d5, q3
-- vqmovun.s16 d6, q12
-- vqmovun.s16 d7, q13
--
-- vmovl.u8 q12, d28
-- vmovl.u8 q13, d29
-- vmovl.u8 q14, d30
-- vmovl.u8 q15, d31
--
-- vaddw.s8 q12, d20
-- vaddw.s8 q13, d21
-- vaddw.s8 q14, d22
-- vaddw.s8 q15, d23
--
-- vqmovun.s16 d8, q12
-- vqmovun.s16 d9, q13
-- vqmovun.s16 d10, q14
-- vqmovun.s16 d11, q15
--
-- vst1.8 {q2-q3}, [r0,:128]!
-- vst1.8 {q4-q5}, [r0,:128], r2
-- sub r0, #32
-- bne 1b
-+ init_sao_band
-+1: subs r12, #1
-+ vld1.8 {q2-q3}, [r1,:128]!
-+ sao_band_32
-+ vst1.8 {q2-q3}, [r0,:128]!
-+ vld1.8 {q2-q3}, [r1,:128], r3
-+ sub r1, #32
-+ sao_band_32
-+ vst1.8 {q2-q3}, [r0,:128], r2
-+ sub r0, #32
-+ bne 1b
-
- bx lr
- endfunc
---
-2.5.0
-
-
-From f93646a97bc885b81759e774d04be3781916a3e7 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Wed, 7 Jan 2015 15:27:38 +0200
-Subject: [PATCH 6/9] More SAO NEON optimizations Now uses only 8 bit integers
- for SAO calculations
-
----
- libavcodec/arm/hevcdsp_init_neon.c | 7 +-
- libavcodec/arm/hevcdsp_sao_neon.S | 664 +++++++++++++++----------------------
- 2 files changed, 272 insertions(+), 399 deletions(-)
-
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index 6379810..8d6e863 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -225,7 +225,7 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
- int x, y;
-
- for (x = 0; x < 5; x++) {
-- sao_offset_val[x] = _sao_offset_val[x];
-+ sao_offset_val[x] = _sao_offset_val[edge_idx[x]];
- }
-
- stride_src /= sizeof(pixel);
-@@ -271,8 +271,9 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
- for (x = 0; x < width; x++) {
- int diff0 = CMP(src[x], src[x + a_stride]);
- int diff1 = CMP(src[x], src[x + b_stride]);
-- int offset_val = edge_idx[2 + diff0 + diff1];
-- dst[x] = av_clip_pixel(src[x] + sao_offset_val[offset_val]);
-+ int idx = diff0 + diff1;
-+ if (idx)
-+ dst[x] = av_clip_pixel(src[x] + sao_offset_val[idx+2]);
- }
- src += stride_src;
- dst += stride_dst;
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index 8852550..5fc482b 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -1,5 +1,5 @@
- /*
-- * Copyright (c) 2014 Seppo Tomperi
-+ * Copyright (c) 2014 - 2015 Seppo Tomperi
- *
- * This file is part of FFmpeg.
- *
-@@ -23,6 +23,7 @@
-
- .macro init_sao_band
- ldr r12, [sp, #0] // offset_table address
-+ pld [r1]
- vld1.8 {q0, q1}, [r12] // offset table
- ldr r12, [sp, #4] // height
- .endm
-@@ -30,36 +31,31 @@
- .macro sao_band_32
- vshr.u8 q8, q2, #3
- vshr.u8 q9, q3, #3
-+ vmov.u8 q14, #128
- vtbl.8 d16, {q0, q1}, d16
- vtbl.8 d17, {q0, q1}, d17
- vtbl.8 d18, {q0, q1}, d18
- vtbl.8 d19, {q0, q1}, d19
-- vmovl.u8 q12, d4
-- vmovl.u8 q13, d5
-- vmovl.u8 q14, d6
-- vmovl.u8 q15, d7
-- vaddw.s8 q12, d16
-- vaddw.s8 q13, d17
-- vaddw.s8 q14, d18
-- vaddw.s8 q15, d19
-- vqmovun.s16 d4, q12
-- vqmovun.s16 d5, q13
-- vqmovun.s16 d6, q14
-- vqmovun.s16 d7, q15
-+ vadd.s8 q2, q14
-+ vadd.s8 q3, q14
-+ vqadd.s8 q2, q8
-+ vqadd.s8 q3, q9
-+ vsub.s8 q2, q14
-+ vsub.s8 q3, q14
- .endm
-
- function ff_hevc_sao_band_w8_neon_8, export=1
- init_sao_band
- 1: subs r12, #4
-- vld1.8 {d4}, [r1,:64], r3
-- vld1.8 {d5}, [r1,:64], r3
-- vld1.8 {d6}, [r1,:64], r3
-- vld1.8 {d7}, [r1,:64], r3
-+ vld1.8 {d4}, [r1, :64], r3
-+ vld1.8 {d5}, [r1, :64], r3
-+ vld1.8 {d6}, [r1, :64], r3
-+ vld1.8 {d7}, [r1, :64], r3
- sao_band_32
-- vst1.8 {d4}, [r0,:64], r2
-- vst1.8 {d5}, [r0,:64], r2
-- vst1.8 {d6}, [r0,:64], r2
-- vst1.8 {d7}, [r0,:64], r2
-+ vst1.8 {d4}, [r0, :64], r2
-+ vst1.8 {d5}, [r0, :64], r2
-+ vst1.8 {d6}, [r0, :64], r2
-+ vst1.8 {d7}, [r0, :64], r2
- bne 1b
-
- bx lr
-@@ -68,11 +64,11 @@ endfunc
- function ff_hevc_sao_band_w16_neon_8, export=1
- init_sao_band
- 1: subs r12, #2
-- vld1.8 {q2}, [r1,:128], r3
-- vld1.8 {q3}, [r1,:128], r3
-+ vld1.8 {q2}, [r1, :128], r3
-+ vld1.8 {q3}, [r1, :128], r3
- sao_band_32
-- vst1.8 {q2}, [r0,:128], r2
-- vst1.8 {q3}, [r0,:128], r2
-+ vst1.8 {q2}, [r0, :128], r2
-+ vst1.8 {q3}, [r0, :128], r2
- bne 1b
-
- bx lr
-@@ -81,9 +77,9 @@ endfunc
- function ff_hevc_sao_band_w32_neon_8, export=1
- init_sao_band
- 1: subs r12, #1
-- vld1.8 {q2-q3}, [r1,:128], r3
-+ vld1.8 {q2-q3}, [r1, :128], r3
- sao_band_32
-- vst1.8 {q2-q3}, [r0,:128], r2
-+ vst1.8 {q2-q3}, [r0, :128], r2
- bne 1b
-
- bx lr
-@@ -92,263 +88,153 @@ endfunc
- function ff_hevc_sao_band_w64_neon_8, export=1
- init_sao_band
- 1: subs r12, #1
-- vld1.8 {q2-q3}, [r1,:128]!
-+ pld [r1, r3]
-+ vld1.8 {q2-q3}, [r1, :128]!
- sao_band_32
-- vst1.8 {q2-q3}, [r0,:128]!
-- vld1.8 {q2-q3}, [r1,:128], r3
-+ vst1.8 {q2-q3}, [r0, :128]!
-+ vld1.8 {q2-q3}, [r1, :128], r3
- sub r1, #32
- sao_band_32
-- vst1.8 {q2-q3}, [r0,:128], r2
-+ vst1.8 {q2-q3}, [r0, :128], r2
- sub r0, #32
- bne 1b
-
- bx lr
- endfunc
--
-+// input
-+// a in q0 - q3
-+// c in q4 - q7
-+// b in q8 - q11
-+// offset table in r7 and r5
-+// output in q0 - q3
-+// clobbers q12 - q15
- .macro edge_w64_body
-- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
-- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
-- vcgt.u8 q13, q5, q1
-- vcgt.u8 q1, q1, q5
-- vcgt.u8 q14, q6, q2
-- vcgt.u8 q2, q2, q6
-- vcgt.u8 q15, q7, q3
-- vcgt.u8 q3, q3, q7
--
-- vsub.s8 q12, q0, q12 // diff0
-- vsub.s8 q13, q1, q13
-- vsub.s8 q14, q2, q14
-- vsub.s8 q15, q3, q15
--
-+ vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
-+ vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
-+ vcgt.u8 q13, q5, q1
-+ vcgt.u8 q1, q1, q5
-+ vsub.s8 q12, q0, q12 // diff0
- vcgt.u8 q0, q4, q8 // c > b
-- vcgt.u8 q8, q8, q4 // b > c
-+ vsub.s8 q13, q1, q13
-+
-+ vcgt.u8 q14, q8, q4 // b > c
- vcgt.u8 q1, q5, q9
-- vcgt.u8 q9, q9, q5
-- vcgt.u8 q2, q6, q10
-- vcgt.u8 q10, q10, q6
-- vcgt.u8 q3, q7, q11
-- vcgt.u8 q11, q11, q7
-+ vcgt.u8 q15, q9, q5
-+ vsub.s8 q0, q14, q0 // diff1
-
-- vsub.s8 q0, q8, q0 // diff1
-- vsub.s8 q1, q9, q1
-- vsub.s8 q2, q10, q2
-- vsub.s8 q3, q11, q3
-+ vsub.s8 q1, q15, q1
-
-- vadd.s8 q0, q12 //diff0 + diff1
-- vadd.s8 q1, q13
-- vadd.s8 q2, q14
-- vadd.s8 q3, q15
--
-- vdup.s8 q9, r6 // 3 to all elements
-- sub r6, #1
--
-- vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
-- vclt.s8 q13, q1, #0
-- vclt.s8 q14, q2, #0
-- vclt.s8 q15, q3, #0
--
-- vadd.s8 q8, q0, q9 // diff0 + diff1 + 3
-- vadd.s8 q10, q1, q9
-- vand.8 q12, q8, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
-- vand.8 q13, q10, q13
-- vadd.s8 q8, q2, q9
-- vadd.s8 q10, q3, q9
-- vand.8 q14, q8, q14
-- vand.8 q15, q10, q15
--
-- vdup.s8 q9, r6 // 2 to all elements
-- add r6, #1
--
-- vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
-- vadd.s8 q8, q0, q9 // diff0 + diff1 + 2
-- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-- vcgt.s8 q10, q1, #0
-- vadd.s8 q0, q11, q12 // offset_idx
--
-- vadd.s8 q8, q1, q9 // diff0 + diff1 + 2
-- vcgt.s8 q12, q2, #0
-- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-- vadd.s8 q8, q2, q9 // diff0 + diff1 + 2
-- vadd.s8 q1, q11, q13
--
-- vand.8 q11, q8, q12 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-- vcgt.s8 q10, q3, #0
-- vadd.s8 q2, q11, q14
--
-- vadd.s8 q8, q3, q9 // diff0 + diff1 + 2
-- vmov.32 d18[0], r7 // load offset table from general registers
-- vand.8 q11, q8, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-- vmov.32 d18[1], r5 // load rest of offset table
-- vadd.s8 q3, q11, q15
--
-- vtbl.8 d0, {d18}, d0
-- vtbl.8 d1, {d18}, d1
-- vtbl.8 d2, {d18}, d2
-- vtbl.8 d3, {d18}, d3
-- vtbl.8 d4, {d18}, d4
-- vtbl.8 d5, {d18}, d5
-- vtbl.8 d6, {d18}, d6
-- vtbl.8 d7, {d18}, d7
--
-- vmovl.u8 q8, d8
-- vmovl.u8 q9, d9
-- vmovl.u8 q10, d10
-- vmovl.u8 q11, d11
-- vmovl.u8 q12, d12
-- vmovl.u8 q13, d13
-- vmovl.u8 q14, d14
-- vmovl.u8 q15, d15
--
-- vaddw.s8 q8, d0
-- vaddw.s8 q9, d1
-- vaddw.s8 q10, d2
-- vaddw.s8 q11, d3
-- vaddw.s8 q12, d4
-- vaddw.s8 q13, d5
-- vaddw.s8 q14, d6
-- vaddw.s8 q15, d7
--
-- vqmovun.s16 d0, q8
-- vqmovun.s16 d1, q9
-- vqmovun.s16 d2, q10
-- vqmovun.s16 d3, q11
-- vqmovun.s16 d4, q12
-- vqmovun.s16 d5, q13
-- vqmovun.s16 d6, q14
-- vqmovun.s16 d7, q15
--
-- vstm r0, {q0-q3}
-- add r0, r2
--.endm
-+ vadd.s8 q0, q12 //diff0 + diff1
-+ vadd.s8 q1, q13
-
--.macro edge_w32_body
-- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
-- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
-- vcgt.u8 q13, q5, q1
-- vcgt.u8 q1, q1, q5
-+ vcgt.u8 q14, q6, q2
-+ vcgt.u8 q2, q2, q6
-+ vcgt.u8 q15, q7, q3
-+ vcgt.u8 q3, q3, q7
-
-- vsub.s8 q12, q0, q12 // diff0
-- vcgt.u8 q0, q4, q8 // c > b
-- vsub.s8 q13, q1, q13 // diff0 part 2
-+ vsub.s8 q14, q2, q14
-+ vcgt.u8 q2, q6, q10
-+ vsub.s8 q15, q3, q15
-
-- vcgt.u8 q6, q8, q4 // b > c
-- vcgt.u8 q1, q5, q9
-- vcgt.u8 q7, q9, q5
-+ vcgt.u8 q12, q10, q6
-+ vcgt.u8 q3, q7, q11
-+ vcgt.u8 q13, q11, q7
-+ vsub.s8 q2, q12, q2
-+ vsub.s8 q3, q13, q3
-
-- vsub.s8 q0, q6, q0 // diff1
-- vsub.s8 q1, q7, q1 // diff1 part 2
-- vadd.s8 q0, q12 //diff0 + diff1
-+ vmov.s8 q13, #2 // 2 to all elements
-
-- vdup.s8 q7, r6 // 3 to all elements
-- sub r6, #1
-- vadd.s8 q1, q13
-+ vadd.s8 q2, q14
-+ vadd.s8 q3, q15
-+
-+ vmov.32 d24[0], r4 // load offset table from general registers
-+ vmov.32 d24[1], r5 // load rest of offset table
-
-- vclt.s8 q12, q0, #0 // diff0 + diff1 < 0
-- vclt.s8 q13, q1, #0
--
-- vadd.s8 q6, q0, q7 // diff0 + diff1 + 3
-- vadd.s8 q10, q1, q7
-- vdup.s8 q7, r6 // 2 to all elements
-- add r6, #1
-- vand.8 q12, q6, q12 // if (diff0 + diff1 < 0) then (diff0 + diff1 + 3) else 0
-- vand.8 q13, q10, q13
--
--
-- vcgt.s8 q10, q0, #0 // diff0 + diff1 > 0
-- vadd.s8 q6, q0, q7 // diff0 + diff1 + 2
-- vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-- vcgt.s8 q10, q1, #0
-- vadd.s8 q0, q11, q12 // offset_idx
--
-- vadd.s8 q6, q1, q7 // diff0 + diff1 + 2
-- vmov.32 d14[0], r7 // load offset table from general registers
-- vand.8 q11, q6, q10 // if (diff0 + diff1 > 0) then (diff0 + diff1 + 2) else 0
-- vmov.32 d14[1], r5 // load rest of offset table
-- vadd.s8 q1, q11, q13
--
-- vtbl.8 d0, {d14}, d0
-- vtbl.8 d1, {d14}, d1
-- vtbl.8 d2, {d14}, d2
-- vtbl.8 d3, {d14}, d3
--
-- vmovl.u8 q6, d8
-- vmovl.u8 q7, d9
-- vmovl.u8 q10, d10
-- vmovl.u8 q11, d11
--
-- vaddw.s8 q6, d0
-- vaddw.s8 q7, d1
-- vaddw.s8 q10, d2
-- vaddw.s8 q11, d3
--
-- vqmovun.s16 d0, q6
-- vqmovun.s16 d1, q7
-- vqmovun.s16 d2, q10
-- vqmovun.s16 d3, q11
--
-- vstm r0, {q0-q1}
-- add r0, r2
-+ vadd.s8 q0, q13
-+ vadd.s8 q1, q13
-+ vadd.s8 q2, q13
-+ vadd.s8 q3, q13
-+
-+ vmov.u8 q15, #128 // s8 #-128
-+ vtbl.8 d0, {d24}, d0
-+ vtbl.8 d1, {d24}, d1
-+ vtbl.8 d2, {d24}, d2
-+ vtbl.8 d3, {d24}, d3
-+ vtbl.8 d4, {d24}, d4
-+ vtbl.8 d5, {d24}, d5
-+ vtbl.8 d6, {d24}, d6
-+ vtbl.8 d7, {d24}, d7
-+
-+ vadd.s8 q12, q4, q15
-+ vadd.s8 q13, q5, q15
-+ vadd.s8 q14, q6, q15
-+ vadd.s8 q15, q7, q15
-+ vqadd.s8 q12, q0
-+ vqadd.s8 q15, q3
-+ vmov.u8 q3, #128 // s8 #-128
-+ vqadd.s8 q13, q1
-+ vqadd.s8 q14, q2
-+ vsub.s8 q0, q12, q3
-+ vsub.s8 q1, q13, q3
-+ vsub.s8 q2, q14, q3
-+ vsub.s8 q3, q15, q3
-+ vst1.8 {q0-q1}, [r0, :128]!
-+ vst1.8 {q2-q3}, [r0, :128], r2
-+ sub r0, #32
- .endm
-
--function ff_hevc_sao_edge_eo0_w64_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-+.macro init_edge_64
-+ push {r4-r5}
-+ ldr r12, [sp, #8] // height
-+ ldr r5, [sp, #12] // sao_offset_val_table
-+ ldr r4, [r5]
- add r5, #4
- ldr r5, [r5]
-+.endm
-+
-+function ff_hevc_sao_edge_eo0_w64_neon_8, export=1
-+ init_edge_64
- vpush {d8-d15}
- sub r1, #8
--1: subs r4, #1
-- vld1.64 {q10-q11}, [r1]!
-- vld1.64 {q12-q13}, [r1]!
-- vld1.64 {q14}, [r1], r3
-- sub r1, #64
-+1: subs r12, #1
-+ vld1.64 {d7}, [r1, :64]!
-+ vld1.64 {q4-q5}, [r1, :128]! // load c
-+ vld1.64 {q6-q7}, [r1, :128]!
-+ vld1.64 {d24}, [r1, :64], r3
-+ sub r1, #72
- // load a
-- vext.8 q0, q10, q11, #7
-- vext.8 q1, q11, q12, #7
-- vext.8 q2, q12, q13, #7
-- vext.8 q3, q13, q14, #7
-- // load c
-- vext.8 q4, q10, q11, #8
-- vext.8 q5, q11, q12, #8
-- vext.8 q6, q12, q13, #8
-- vext.8 q7, q13, q14, #8
-+ vext.8 q0, q3, q4, #15
-+ vext.8 q1, q4, q5, #15
-+ vext.8 q2, q5, q6, #15
-+ vext.8 q3, q6, q7, #15
- // load b
-- vext.8 q8, q10, q11, #9
-- vext.8 q9, q11, q12, #9
-- vext.8 q10, q12, q13, #9
-- vext.8 q11, q13, q14, #9
-+ vext.8 q8, q4, q5, #1
-+ vext.8 q9, q5, q6, #1
-+ vext.8 q10, q6, q7, #1
-+ vext.8 q11, q7, q12, #1
- edge_w64_body
- bne 1b
- vpop {d8-d15}
-- pop {r4-r8}
-+ pop {r4-r5}
- bx lr
- endfunc
-
- function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-- add r5, #4
-- ldr r5, [r5]
-+ init_edge_64
- vpush {d8-d15}
- sub r1, r3
- // load a
-- vld1.8 {q0-q1}, [r1]!
-- vld1.8 {q2-q3}, [r1], r3
-+ vld1.8 {q0-q1}, [r1, :128]!
-+ vld1.8 {q2-q3}, [r1, :128], r3
- sub r1, #32
--1: subs r4, #1
- // load c
-- vld1.8 {q4-q5}, [r1]!
-- vld1.8 {q6-q7}, [r1], r3
-+ vld1.8 {q4-q5}, [r1, :128]!
-+ vld1.8 {q6-q7}, [r1, :128], r3
- sub r1, #32
-+1: subs r12, #1
- // load b
-- vld1.8 {q8-q9}, [r1]!
-- vld1.8 {q10-q11}, [r1]
-+ vld1.8 {q8-q9}, [r1, :128]!
-+ vld1.8 {q10-q11}, [r1, :128], r3
- sub r1, #32
- edge_w64_body
- // copy c to a
-@@ -356,20 +242,19 @@ function ff_hevc_sao_edge_eo1_w64_neon_8, export=1
- vmov.64 q1, q5
- vmov.64 q2, q6
- vmov.64 q3, q7
-+ // copy b to c
-+ vmov.64 q4, q8
-+ vmov.64 q5, q9
-+ vmov.64 q6, q10
-+ vmov.64 q7, q11
- bne 1b
- vpop {d8-d15}
-- pop {r4-r8}
-+ pop {r4-r5}
- bx lr
- endfunc
-
- function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-- add r5, #4
-- ldr r5, [r5]
-+ init_edge_64
- vpush {d8-d15}
- 1: sub r1, r3
- // load a
-@@ -379,10 +264,10 @@ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
- vld1.8 {q0-q1}, [r1]!
- vld1.8 {q2-q3}, [r1], r3
- sub r1, #31
-- subs r4, #1
-+ subs r12, #1
- // load c
-- vld1.8 {q4-q5}, [r1]!
-- vld1.8 {q6-q7}, [r1], r3
-+ vld1.8 {q4-q5}, [r1, :128]!
-+ vld1.8 {q6-q7}, [r1, :128], r3
- sub r1, #32
- // load b
- add r1, #1
-@@ -390,25 +275,14 @@ function ff_hevc_sao_edge_eo2_w64_neon_8, export=1
- vld1.8 {q10-q11}, [r1]
- sub r1, #33
- edge_w64_body
-- // copy c to a
-- vmov.64 q0, q4
-- vmov.64 q1, q5
-- vmov.64 q2, q6
-- vmov.64 q3, q7
- bne 1b
- vpop {d8-d15}
-- pop {r4-r8}
-+ pop {r4-r5}
- bx lr
- endfunc
-
- function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-- add r5, #4
-- ldr r5, [r5]
-+ init_edge_64
- vpush {d8-d15}
- 1: sub r1, r3
- // load a
-@@ -418,10 +292,10 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
- vld1.8 {q0-q1}, [r1]!
- vld1.8 {q2-q3}, [r1], r3
- sub r1, #33
-- subs r4, #1
-+ subs r12, #1
- // load c
-- vld1.8 {q4-q5}, [r1]!
-- vld1.8 {q6-q7}, [r1], r3
-+ vld1.8 {q4-q5}, [r1, :128]!
-+ vld1.8 {q6-q7}, [r1, :128], r3
- sub r1, #32
- // load b
- sub r1, #1
-@@ -429,178 +303,176 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
- vld1.8 {q10-q11}, [r1]
- sub r1, #31
- edge_w64_body
-- // copy c to a
-- vmov.64 q0, q4
-- vmov.64 q1, q5
-- vmov.64 q2, q6
-- vmov.64 q3, q7
- bne 1b
- vpop {d8-d15}
-- pop {r4-r8}
-+ pop {r4-r5}
- bx lr
- endfunc
-
-+// inputs:
-+// a in q0, q1
-+// c in q2, q3
-+// b in q8, q9
-+// offset table in d31
-+// clobbered registers q0, q1, q10, q11, q12, q13
-+// output q0, q1
-+.macro edge_w32_body
-+ vcgt.u8 q12, q2, q0 // c > a -> -1 , otherwise 0
-+ vcgt.u8 q0, q0, q2 // a > c -> -1 , otherwise 0
-+ vcgt.u8 q13, q3, q1
-+ vcgt.u8 q1, q1, q3
-+
-+ vsub.s8 q12, q0, q12 // diff0
-+ vcgt.u8 q0, q2, q8 // c > b
-+ vsub.s8 q13, q1, q13 // diff0 part 2
-+
-+ vcgt.u8 q10, q8, q2 // b > c
-+ vcgt.u8 q1, q3, q9
-+ vcgt.u8 q11, q9, q3
-+
-+ vsub.s8 q0, q10, q0 // diff1
-+
-+ vmov.s8 q10, #2 // 2 to all elements
-+ vsub.s8 q1, q11, q1 // diff1 part 2
-+ vadd.s8 q0, q12 //diff0 + diff1
-+ vadd.s8 q1, q13
-+
-+ vadd.s8 q0, q10
-+ vadd.s8 q1, q10
-+
-+ vmov.u8 q10, #128
-+ vtbl.8 d0, {d31}, d0
-+ vtbl.8 d1, {d31}, d1
-+ vtbl.8 d2, {d31}, d2
-+ vtbl.8 d3, {d31}, d3
-+
-+ vadd.s8 q11, q2, q10
-+ vadd.s8 q12, q3, q10
-+ vqadd.s8 q11, q0
-+ vqadd.s8 q12, q1
-+ vsub.s8 q0, q11, q10
-+ vsub.s8 q1, q12, q10
-+ vst1.8 {q0-q1}, [r0, :128], r2
-+.endm
-+
-+.macro init_edge_32
-+ ldr r12, [sp, #4] // sao_offset_val_table
-+ vld1.32 {d31}, [r12]
-+ ldr r12, [sp] // height
-+.endm
-+
- function ff_hevc_sao_edge_eo0_w32_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-- add r5, #4
-- ldr r5, [r5]
-- vpush {d8-d15}
-- sub r1, #8 // load 8 extra bytes
--1: subs r4, #1
-- vld1.8 {q10-q11}, [r1]
-- add r1, #32
-- vld1.8 {q12}, [r1], r3 // only first 9 bytes are used
-- sub r1, #32
-+ init_edge_32
-+ sub r1, #4 // load 4 extra bytes
-+1: subs r12, #1
-+ vld1.32 d3[1], [r1]!
-+ vld1.8 {q2-q3}, [r1, :128]! // c
-+ vld1.32 d20[0], [r1], r3
-+ sub r1, #36
- // a
-- vext.8 q0, q10, q11, #7
-- vext.8 q1, q11, q12, #7
-- // c
-- vext.8 q4, q10, q11, #8
-- vext.8 q5, q11, q12, #8
-+ vext.8 q0, q1, q2, #15
-+ vext.8 q1, q2, q3, #15
- // b
-- vext.8 q8, q10, q11, #9
-- vext.8 q9, q11, q12, #9
-+ vext.8 q8, q2, q3, #1
-+ vext.8 q9, q3, q10, #1
- edge_w32_body
-- bne 1b
-- vpop {d8-d15}
-- pop {r4-r8}
-- bx lr
-+ bne 1b
-+ bx lr
- endfunc
-
- function ff_hevc_sao_edge_eo1_w32_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-- add r5, #4
-- ldr r5, [r5]
-- vpush {d8-d15}
-+ init_edge_32
- // load a
- sub r1, r3
-- vld1.8 {q0-q1}, [r1], r3
-+ vld1.8 {q0-q1}, [r1, :128], r3
- // load c
-- vld1.8 {q4-q5}, [r1], r3
--1: subs r4, #1
-+ vld1.8 {q2-q3}, [r1, :128], r3
-+1: subs r12, #1
- // load b
-- vld1.8 {q8-q9}, [r1], r3
-+ vld1.8 {q8-q9}, [r1, :128], r3
- edge_w32_body
- // inputs for next loop iteration
- // a
-- vmov.64 q0, q4
-- vmov.64 q1, q5
-+ vmov.64 q0, q2
-+ vmov.64 q1, q3
- // c
-- vmov.64 q4, q8
-- vmov.64 q5, q9
-- bne 1b
-- vpop {d8-d15}
-- pop {r4-r8}
-- bx lr
-+ vmov.64 q2, q8
-+ vmov.64 q3, q9
-+ bne 1b
-+ bx lr
- endfunc
-
- function ff_hevc_sao_edge_eo2_w32_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-- add r5, #4
-- ldr r5, [r5]
-- vpush {d8-d15}
-+ init_edge_32
-+ vpush {d8-d15}
- // load a
- sub r1, r3
-- sub r1, #8
-- vld1.8 {q10-q11}, [r1]
-- add r1, #32
-- vld1.8 {q12}, [r1], r3
-- sub r1, #32
-+ sub r1, #8
-+ vld1.8 {q10-q11}, [r1, :64]!
-+ vld1.8 {d24}, [r1, :64], r3
-+ sub r1, #32
- vext.8 q0, q10, q11, #7
- vext.8 q1, q11, q12, #7
- // load c
-- vld1.8 {q10-q11}, [r1]
-- add r1, #32
-- vld1.8 {q12}, [r1], r3
-- sub r1, #32
-- vext.8 q4, q10, q11, #8
-- vext.8 q5, q11, q12, #8
-- vext.8 q2, q10, q11, #7
--1: subs r4, #1
-+ vld1.8 {d9}, [r1, :64]!
-+ vld1.8 {q2-q3}, [r1, :64], r3
-+ sub r1, #8
-+ vext.8 q4, q4, q2, #15
-+1: subs r12, #1
- // load b
-- vld1.8 {q10-q11}, [r1]
-- add r1, #32
-- vld1.8 {q12}, [r1], r3
-- sub r1, #32
-+ vld1.8 {q10-q11}, [r1, :64]!
-+ vld1.8 {q12}, [r1, :64], r3
-+ sub r1, #32
- vext.8 q8, q10, q11, #9
- vext.8 q9, q11, q12, #9
-- vext.8 q14, q10, q11, #8
-- vext.8 q15, q11, q12, #8
-- vext.8 q3, q10, q11, #7
-+ vext.8 q6, q10, q11, #8
-+ vext.8 q7, q11, q12, #8
-+ vext.8 q5, q10, q11, #7
- edge_w32_body
- // inputs for next loop iteration
- // a
-- vmov.8 q0, q2
-- vext.8 q1, q4, q5, #15
-+ vmov.8 q0, q4
-+ vext.8 q1, q2, q3, #15
- // c
-- vmov.8 q4, q14
-- vmov.8 q5, q15
-- vmov.8 q2, q3
-- bne 1b
-- vpop {d8-d15}
-- pop {r4-r8}
-- bx lr
-+ vmov.8 q2, q6
-+ vmov.8 q3, q7
-+ vmov.8 q4, q5
-+ bne 1b
-+ vpop {d8-d15}
-+ bx lr
- endfunc
-
- function ff_hevc_sao_edge_eo3_w32_neon_8, export=1
-- push {r4-r8}
-- ldr r4, [sp, #20] // height
-- ldr r5, [sp, #24] // sao_offset_val_table
-- ldr r6, =0x03
-- ldr r7, [r5]
-- add r5, #4
-- sub r1, r3
-- ldr r5, [r5]
-- sub r1, #8
-- vpush {d8-d15}
-+ init_edge_32
-+ sub r1, r3
- // load a
-- vld1.8 {q10-q11}, [r1]
-- add r1, #32
-- vld1.8 {q12}, [r1], r3
-- sub r1, #32
-- vext.8 q0, q10, q11, #9
-- vext.8 q1, q11, q12, #9
-+ vld1.8 {q10-q11}, [r1, :64]!
-+ vld1.8 {d24}, [r1, :64], r3
-+ sub r1, #32
-+ vext.8 q0, q10, q11, #1
-+ vext.8 q1, q11, q12, #1
- // load c
-- vld1.8 {q10-q11}, [r1]
-- add r1, #32
-- vld1.8 {q12}, [r1], r3
-- sub r1, #32
-- vext.8 q4, q10, q11, #8
-- vext.8 q5, q11, q12, #8
-- vext.8 q2, q12, q11, #8
--1: subs r4, #1
-+ vld1.8 {q2-q3}, [r1, :64]!
-+ vld1.8 {d30}, [r1, :64], r3
-+ sub r1, #40
-+1: subs r12, #1
- // load b
-- vld1.8 {q10-q11}, [r1]
-- add r1, #32
-- vld1.8 {q12}, [r1], r3
-- sub r1, #32
-+ vld1.8 {q10-q11}, [r1, :64]!
-+ vld1.8 {q12}, [r1, :64], r3
-+ sub r1, #32
- vext.8 q8, q10, q11, #7
- vext.8 q9, q11, q12, #7
-- vext.8 q3, q12, q10, #7
-+ vext.8 q14, q12, q10, #7
- edge_w32_body
- // inputs for next loop iteration
- // a
-- vext.8 q0, q4, q5, #1
-- vext.8 q1, q5, q2, #1
-+ vext.8 q0, q2, q3, #1
-+ vext.8 q1, q3, q15, #1
- // c
-- vext.8 q4, q8, q9, #1
-- vext.8 q5, q9, q3, #1
-- vext.8 q2, q3, q1, #1
-- bne 1b
-- vpop {d8-d15}
-- pop {r4-r8}
-- bx lr
-+ vext.8 q2, q8, q9, #1
-+ vext.8 q3, q9, q14, #1
-+ vext.8 d30, d28, d2, #1
-+ bne 1b
-+ bx lr
- endfunc
-
---
-2.5.0
-
-
-From 016c39d46b86830204a4519590332d2a38f7ee51 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Thu, 8 Jan 2015 09:58:55 +0200
-Subject: [PATCH 7/9] small optimization to SAO BAND. correct path for
- bit_depth_template.c
-
----
- libavcodec/arm/hevcdsp_init_neon.c | 2 +-
- libavcodec/arm/hevcdsp_sao_neon.S | 2 +-
- 2 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index 8d6e863..385c35d 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -23,7 +23,7 @@
- #include "libavcodec/hevcdsp.h"
- #include "hevcdsp_arm.h"
- #include "libavcodec/avcodec.h"
--#include "../bit_depth_template.c"
-+#include "libavcodec/bit_depth_template.c"
-
- void ff_hevc_v_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
- void ff_hevc_h_loop_filter_luma_neon(uint8_t *_pix, ptrdiff_t _stride, int _beta, int *_tc, uint8_t *_no_p, uint8_t *_no_q);
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index 5fc482b..710b32b 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -26,12 +26,12 @@
- pld [r1]
- vld1.8 {q0, q1}, [r12] // offset table
- ldr r12, [sp, #4] // height
-+ vmov.u8 q14, #128
- .endm
-
- .macro sao_band_32
- vshr.u8 q8, q2, #3
- vshr.u8 q9, q3, #3
-- vmov.u8 q14, #128
- vtbl.8 d16, {q0, q1}, d16
- vtbl.8 d17, {q0, q1}, d17
- vtbl.8 d18, {q0, q1}, d18
---
-2.5.0
-
-
-From 579f1584d688e1ac24fb7d22697e2a7b64f62e8e Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Fri, 9 Jan 2015 10:28:52 +0200
-Subject: [PATCH 8/9] Added height check for SAO NEON optimizations. Faster SAO
- band NEON Some reordering to use NEON pipelines more efficiently
-
----
- libavcodec/arm/hevcdsp_init_neon.c | 12 +++-
- libavcodec/arm/hevcdsp_sao_neon.S | 142 ++++++++++++++++++++++---------------
- 2 files changed, 93 insertions(+), 61 deletions(-)
-
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index 385c35d..6d0689c 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -176,6 +176,7 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
- int8_t offset_table[32] = { 0 };
- int k, y, x;
- int shift = 3; // BIT_DEPTH - 5
-+ int cwidth = 0;
-
- stride_src /= sizeof(pixel);
- stride_dst /= sizeof(pixel);
-@@ -183,7 +184,10 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
- for (k = 0; k < 4; k++)
- offset_table[(k + sao_left_class) & 31] = sao_offset_val[k + 1];
-
-- switch(width){
-+ if (height % 8 == 0)
-+ cwidth = width;
-+
-+ switch(cwidth){
- case 8:
- ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
- break;
-@@ -223,15 +227,19 @@ static void ff_hevc_sao_edge_neon_wrapper(uint8_t *_dst /* align 16 */, uint8_t
- pixel *src = (pixel *)_src;
- int a_stride, b_stride;
- int x, y;
-+ int cwidth = 0;
-
- for (x = 0; x < 5; x++) {
- sao_offset_val[x] = _sao_offset_val[edge_idx[x]];
- }
-
-+ if (height % 8 == 0)
-+ cwidth = width;
-+
- stride_src /= sizeof(pixel);
- stride_dst /= sizeof(pixel);
-
-- switch (width) {
-+ switch (cwidth) {
- case 32:
- switch(eo) {
- case 0:
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index 710b32b..08f50b8 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -26,36 +26,59 @@
- pld [r1]
- vld1.8 {q0, q1}, [r12] // offset table
- ldr r12, [sp, #4] // height
-- vmov.u8 q14, #128
-+ vmov.u8 q3, #128
- .endm
-
--.macro sao_band_32
-- vshr.u8 q8, q2, #3
-- vshr.u8 q9, q3, #3
-- vtbl.8 d16, {q0, q1}, d16
-- vtbl.8 d17, {q0, q1}, d17
-- vtbl.8 d18, {q0, q1}, d18
-- vtbl.8 d19, {q0, q1}, d19
-- vadd.s8 q2, q14
-- vadd.s8 q3, q14
-- vqadd.s8 q2, q8
-- vqadd.s8 q3, q9
-- vsub.s8 q2, q14
-- vsub.s8 q3, q14
-+// 128 in q3
-+// input q8 - q11
-+// 32 cycles
-+.macro sao_band_64
-+ vshr.u8 q12, q8, #3
-+ vshr.u8 q13, q9, #3
-+ vshr.u8 q14, q10, #3
-+ vshr.u8 q15, q11, #3
-+ vtbl.8 d24, {d0, d1, d2, d3}, d24
-+ vadd.s8 q8, q3
-+ vtbl.8 d25, {d0, d1, d2, d3}, d25
-+ vadd.s8 q9, q3
-+ vtbl.8 d26, {d0, d1, d2, d3}, d26
-+ vadd.s8 q10, q3
-+ vtbl.8 d27, {d0, d1, d2, d3}, d27
-+ vadd.s8 q11, q3
-+ vtbl.8 d28, {d0, d1, d2, d3}, d28
-+ vqadd.s8 q8, q12
-+ vtbl.8 d29, {d0, d1, d2, d3}, d29
-+ vqadd.s8 q9, q13
-+ vtbl.8 d30, {d0, d1, d2, d3}, d30
-+ vqadd.s8 q10, q14
-+ vtbl.8 d31, {d0, d1, d2, d3}, d31
-+ vqadd.s8 q11, q15
-+ vsub.s8 q8, q3
-+ vsub.s8 q9, q3
-+ vsub.s8 q10, q3
-+ vsub.s8 q11, q3
- .endm
-
- function ff_hevc_sao_band_w8_neon_8, export=1
- init_sao_band
--1: subs r12, #4
-- vld1.8 {d4}, [r1, :64], r3
-- vld1.8 {d5}, [r1, :64], r3
-- vld1.8 {d6}, [r1, :64], r3
-- vld1.8 {d7}, [r1, :64], r3
-- sao_band_32
-- vst1.8 {d4}, [r0, :64], r2
-- vst1.8 {d5}, [r0, :64], r2
-- vst1.8 {d6}, [r0, :64], r2
-- vst1.8 {d7}, [r0, :64], r2
-+1: subs r12, #8
-+ vld1.8 {d16}, [r1, :64], r3
-+ vld1.8 {d17}, [r1, :64], r3
-+ vld1.8 {d18}, [r1, :64], r3
-+ vld1.8 {d19}, [r1, :64], r3
-+ vld1.8 {d20}, [r1, :64], r3
-+ vld1.8 {d21}, [r1, :64], r3
-+ vld1.8 {d22}, [r1, :64], r3
-+ vld1.8 {d23}, [r1, :64], r3
-+ sao_band_64
-+ vst1.8 {d16}, [r0, :64], r2
-+ vst1.8 {d17}, [r0, :64], r2
-+ vst1.8 {d18}, [r0, :64], r2
-+ vst1.8 {d19}, [r0, :64], r2
-+ vst1.8 {d20}, [r0, :64], r2
-+ vst1.8 {d21}, [r0, :64], r2
-+ vst1.8 {d22}, [r0, :64], r2
-+ vst1.8 {d23}, [r0, :64], r2
- bne 1b
-
- bx lr
-@@ -63,12 +86,16 @@ endfunc
-
- function ff_hevc_sao_band_w16_neon_8, export=1
- init_sao_band
--1: subs r12, #2
-- vld1.8 {q2}, [r1, :128], r3
-- vld1.8 {q3}, [r1, :128], r3
-- sao_band_32
-- vst1.8 {q2}, [r0, :128], r2
-- vst1.8 {q3}, [r0, :128], r2
-+1: subs r12, #4
-+ vld1.8 {q8}, [r1, :128], r3
-+ vld1.8 {q9}, [r1, :128], r3
-+ vld1.8 {q10}, [r1, :128], r3
-+ vld1.8 {q11}, [r1, :128], r3
-+ sao_band_64
-+ vst1.8 {q8}, [r0, :128], r2
-+ vst1.8 {q9}, [r0, :128], r2
-+ vst1.8 {q10}, [r0, :128], r2
-+ vst1.8 {q11}, [r0, :128], r2
- bne 1b
-
- bx lr
-@@ -76,10 +103,12 @@ endfunc
-
- function ff_hevc_sao_band_w32_neon_8, export=1
- init_sao_band
--1: subs r12, #1
-- vld1.8 {q2-q3}, [r1, :128], r3
-- sao_band_32
-- vst1.8 {q2-q3}, [r0, :128], r2
-+1: subs r12, #2
-+ vld1.8 {q8-q9}, [r1, :128], r3
-+ vld1.8 {q10-q11}, [r1, :128], r3
-+ sao_band_64
-+ vst1.8 {q8-q9}, [r0, :128], r2
-+ vst1.8 {q10-q11}, [r0, :128], r2
- bne 1b
-
- bx lr
-@@ -89,13 +118,12 @@ function ff_hevc_sao_band_w64_neon_8, export=1
- init_sao_band
- 1: subs r12, #1
- pld [r1, r3]
-- vld1.8 {q2-q3}, [r1, :128]!
-- sao_band_32
-- vst1.8 {q2-q3}, [r0, :128]!
-- vld1.8 {q2-q3}, [r1, :128], r3
-+ vld1.8 {q8-q9}, [r1, :128]!
-+ vld1.8 {q10-q11}, [r1, :128], r3
- sub r1, #32
-- sao_band_32
-- vst1.8 {q2-q3}, [r0, :128], r2
-+ sao_band_64
-+ vst1.8 {q8-q9}, [r0, :128]!
-+ vst1.8 {q10-q11}, [r0, :128], r2
- sub r0, #32
- bne 1b
-
-@@ -121,7 +149,6 @@ endfunc
- vcgt.u8 q1, q5, q9
- vcgt.u8 q15, q9, q5
- vsub.s8 q0, q14, q0 // diff1
--
- vsub.s8 q1, q15, q1
-
- vadd.s8 q0, q12 //diff0 + diff1
-@@ -157,27 +184,25 @@ endfunc
-
- vmov.u8 q15, #128 // s8 #-128
- vtbl.8 d0, {d24}, d0
-+ vadd.s8 q13, q4, q15
- vtbl.8 d1, {d24}, d1
-+ vadd.s8 q14, q5, q15
- vtbl.8 d2, {d24}, d2
-+ vqadd.s8 q0, q13
- vtbl.8 d3, {d24}, d3
-+ vqadd.s8 q1, q14
- vtbl.8 d4, {d24}, d4
-+ vadd.s8 q13, q6, q15
- vtbl.8 d5, {d24}, d5
-+ vadd.s8 q14, q7, q15
- vtbl.8 d6, {d24}, d6
-+ vqadd.s8 q2, q13
- vtbl.8 d7, {d24}, d7
--
-- vadd.s8 q12, q4, q15
-- vadd.s8 q13, q5, q15
-- vadd.s8 q14, q6, q15
-- vadd.s8 q15, q7, q15
-- vqadd.s8 q12, q0
-- vqadd.s8 q15, q3
-- vmov.u8 q3, #128 // s8 #-128
-- vqadd.s8 q13, q1
-- vqadd.s8 q14, q2
-- vsub.s8 q0, q12, q3
-- vsub.s8 q1, q13, q3
-- vsub.s8 q2, q14, q3
-- vsub.s8 q3, q15, q3
-+ vqadd.s8 q3, q14
-+ vsub.s8 q0, q15
-+ vsub.s8 q1, q15
-+ vsub.s8 q2, q15
-+ vsub.s8 q3, q15
- vst1.8 {q0-q1}, [r0, :128]!
- vst1.8 {q2-q3}, [r0, :128], r2
- sub r0, #32
-@@ -342,13 +367,12 @@ endfunc
-
- vmov.u8 q10, #128
- vtbl.8 d0, {d31}, d0
-+ vadd.s8 q11, q2, q10
- vtbl.8 d1, {d31}, d1
-+ vadd.s8 q12, q3, q10
- vtbl.8 d2, {d31}, d2
-+ vqadd.s8 q11, q0
- vtbl.8 d3, {d31}, d3
--
-- vadd.s8 q11, q2, q10
-- vadd.s8 q12, q3, q10
-- vqadd.s8 q11, q0
- vqadd.s8 q12, q1
- vsub.s8 q0, q11, q10
- vsub.s8 q1, q12, q10
---
-2.5.0
-
-
-From 026bac1824e4936e948e6b1efec82868c520ea66 Mon Sep 17 00:00:00 2001
-From: Seppo Tomperi
-Date: Mon, 2 Feb 2015 16:08:27 +0200
-Subject: [PATCH 9/9] Further SAO NEON optimisations
-
----
- libavcodec/arm/hevcdsp_init_neon.c | 16 +--
- libavcodec/arm/hevcdsp_sao_neon.S | 224 +++++++++++++++++++------------------
- 2 files changed, 124 insertions(+), 116 deletions(-)
-
-diff --git a/libavcodec/arm/hevcdsp_init_neon.c b/libavcodec/arm/hevcdsp_init_neon.c
-index 6d0689c..e5da7e9 100644
---- a/libavcodec/arm/hevcdsp_init_neon.c
-+++ b/libavcodec/arm/hevcdsp_init_neon.c
-@@ -45,10 +45,10 @@ void ff_hevc_transform_add_16x16_neon_8(uint8_t *_dst, int16_t *coeffs,
- void ff_hevc_transform_add_32x32_neon_8(uint8_t *_dst, int16_t *coeffs,
- ptrdiff_t stride);
-
--void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
--void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
--void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
--void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int8_t * offset_table, int height);
-+void ff_hevc_sao_band_w8_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
-+void ff_hevc_sao_band_w16_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
-+void ff_hevc_sao_band_w32_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
-+void ff_hevc_sao_band_w64_neon_8(uint8_t *_dst, uint8_t *_src, int8_t * offset_table, ptrdiff_t stride_src, ptrdiff_t stride_dst, int height);
-
- void ff_hevc_sao_edge_eo0_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
- void ff_hevc_sao_edge_eo1_w32_neon_8(uint8_t *_dst, uint8_t *_src, ptrdiff_t stride_dst, ptrdiff_t stride_src, int height, int8_t *sao_offset_table);
-@@ -189,16 +189,16 @@ static void ff_hevc_sao_band_neon_wrapper(uint8_t *_dst, uint8_t *_src, ptrdiff_
-
- switch(cwidth){
- case 8:
-- ff_hevc_sao_band_w8_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
-+ ff_hevc_sao_band_w8_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
- break;
- case 16:
-- ff_hevc_sao_band_w16_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
-+ ff_hevc_sao_band_w16_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
- break;
- case 32:
-- ff_hevc_sao_band_w32_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
-+ ff_hevc_sao_band_w32_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
- break;
- case 64:
-- ff_hevc_sao_band_w64_neon_8(_dst, _src, stride_dst, stride_src, offset_table, height);
-+ ff_hevc_sao_band_w64_neon_8(_dst, _src, offset_table, stride_src, stride_dst, height);
- break;
- default:
- for (y = 0; y < height; y++) {
-diff --git a/libavcodec/arm/hevcdsp_sao_neon.S b/libavcodec/arm/hevcdsp_sao_neon.S
-index 08f50b8..9c7808d 100644
---- a/libavcodec/arm/hevcdsp_sao_neon.S
-+++ b/libavcodec/arm/hevcdsp_sao_neon.S
-@@ -22,21 +22,16 @@
- #include "neon.S"
-
- .macro init_sao_band
-- ldr r12, [sp, #0] // offset_table address
- pld [r1]
-- vld1.8 {q0, q1}, [r12] // offset table
-- ldr r12, [sp, #4] // height
-+ vld1.8 {q0, q1}, [r2] // offset table
-+ ldr r2, [sp, #0] // stride_dst
-+ ldr r12, [sp, #4] // height
- vmov.u8 q3, #128
- .endm
-
- // 128 in q3
- // input q8 - q11
--// 32 cycles
- .macro sao_band_64
-- vshr.u8 q12, q8, #3
-- vshr.u8 q13, q9, #3
-- vshr.u8 q14, q10, #3
-- vshr.u8 q15, q11, #3
- vtbl.8 d24, {d0, d1, d2, d3}, d24
- vadd.s8 q8, q3
- vtbl.8 d25, {d0, d1, d2, d3}, d25
-@@ -52,8 +47,8 @@
- vtbl.8 d30, {d0, d1, d2, d3}, d30
- vqadd.s8 q10, q14
- vtbl.8 d31, {d0, d1, d2, d3}, d31
-- vqadd.s8 q11, q15
- vsub.s8 q8, q3
-+ vqadd.s8 q11, q15
- vsub.s8 q9, q3
- vsub.s8 q10, q3
- vsub.s8 q11, q3
-@@ -64,12 +59,16 @@ function ff_hevc_sao_band_w8_neon_8, export=1
- 1: subs r12, #8
- vld1.8 {d16}, [r1, :64], r3
- vld1.8 {d17}, [r1, :64], r3
-+ vshr.u8 q12, q8, #3
- vld1.8 {d18}, [r1, :64], r3
- vld1.8 {d19}, [r1, :64], r3
-+ vshr.u8 q13, q9, #3
- vld1.8 {d20}, [r1, :64], r3
- vld1.8 {d21}, [r1, :64], r3
-+ vshr.u8 q14, q10, #3
- vld1.8 {d22}, [r1, :64], r3
- vld1.8 {d23}, [r1, :64], r3
-+ vshr.u8 q15, q11, #3
- sao_band_64
- vst1.8 {d16}, [r0, :64], r2
- vst1.8 {d17}, [r0, :64], r2
-@@ -88,9 +87,13 @@ function ff_hevc_sao_band_w16_neon_8, export=1
- init_sao_band
- 1: subs r12, #4
- vld1.8 {q8}, [r1, :128], r3
-+ vshr.u8 q12, q8, #3
- vld1.8 {q9}, [r1, :128], r3
-+ vshr.u8 q13, q9, #3
- vld1.8 {q10}, [r1, :128], r3
-+ vshr.u8 q14, q10, #3
- vld1.8 {q11}, [r1, :128], r3
-+ vshr.u8 q15, q11, #3
- sao_band_64
- vst1.8 {q8}, [r0, :128], r2
- vst1.8 {q9}, [r0, :128], r2
-@@ -105,7 +108,11 @@ function ff_hevc_sao_band_w32_neon_8, export=1
- init_sao_band
- 1: subs r12, #2
- vld1.8 {q8-q9}, [r1, :128], r3
-+ vshr.u8 q12, q8, #3
-+ vshr.u8 q13, q9, #3
- vld1.8 {q10-q11}, [r1, :128], r3
-+ vshr.u8 q14, q10, #3
-+ vshr.u8 q15, q11, #3
- sao_band_64
- vst1.8 {q8-q9}, [r0, :128], r2
- vst1.8 {q10-q11}, [r0, :128], r2
-@@ -119,7 +126,11 @@ function ff_hevc_sao_band_w64_neon_8, export=1
- 1: subs r12, #1
- pld [r1, r3]
- vld1.8 {q8-q9}, [r1, :128]!
-+ vshr.u8 q12, q8, #3
-+ vshr.u8 q13, q9, #3
- vld1.8 {q10-q11}, [r1, :128], r3
-+ vshr.u8 q14, q10, #3
-+ vshr.u8 q15, q11, #3
- sub r1, #32
- sao_band_64
- vst1.8 {q8-q9}, [r0, :128]!
-@@ -129,51 +140,18 @@ function ff_hevc_sao_band_w64_neon_8, export=1
-
- bx lr
- endfunc
--// input
--// a in q0 - q3
--// c in q4 - q7
--// b in q8 - q11
--// offset table in r7 and r5
--// output in q0 - q3
--// clobbers q12 - q15
--.macro edge_w64_body
-- vcgt.u8 q12, q4, q0 // c > a -> -1 , otherwise 0
-- vcgt.u8 q0, q0, q4 // a > c -> -1 , otherwise 0
-- vcgt.u8 q13, q5, q1
-- vcgt.u8 q1, q1, q5
-- vsub.s8 q12, q0, q12 // diff0
-- vcgt.u8 q0, q4, q8 // c > b
-- vsub.s8 q13, q1, q13
--
-- vcgt.u8 q14, q8, q4 // b > c
-- vcgt.u8 q1, q5, q9
-- vcgt.u8 q15, q9, q5
-- vsub.s8 q0, q14, q0 // diff1
-- vsub.s8 q1, q15, q1
-
-- vadd.s8 q0, q12 //diff0 + diff1
-- vadd.s8 q1, q13
--
-- vcgt.u8 q14, q6, q2
-- vcgt.u8 q2, q2, q6
-- vcgt.u8 q15, q7, q3
-- vcgt.u8 q3, q3, q7
--
-- vsub.s8 q14, q2, q14
-- vcgt.u8 q2, q6, q10
-- vsub.s8 q15, q3, q15
--
-- vcgt.u8 q12, q10, q6
-- vcgt.u8 q3, q7, q11
-- vcgt.u8 q13, q11, q7
-- vsub.s8 q2, q12, q2
-- vsub.s8 q3, q13, q3
-+.macro diff32 out0, out1, tmp0, tmp1, in0, in1, in2, in3
-+ vcgt.u8 \out0, \in2, \in0 // c > a -> -1 , otherwise 0
-+ vcgt.u8 \tmp0, \in0, \in2 // a > c -> -1 , otherwise 0
-+ vcgt.u8 \out1, \in3, \in1 // c > a -> -1 , otherwise 0 part 2
-+ vcgt.u8 \tmp1, \in1, \in3 // a > c -> -1 , otherwise 0 part 2
-+ vsub.s8 \out0, \tmp0, \out0 // diff0
-+ vsub.s8 \out1, \tmp1, \out1 // diff0 part 2
-+.endm
-
-+.macro table64
- vmov.s8 q13, #2 // 2 to all elements
--
-- vadd.s8 q2, q14
-- vadd.s8 q3, q15
--
- vmov.32 d24[0], r4 // load offset table from general registers
- vmov.32 d24[1], r5 // load rest of offset table
-
-@@ -208,6 +186,28 @@ endfunc
- sub r0, #32
- .endm
-
-+// input
-+// a in q0 - q3
-+// c in q4 - q7
-+// b in q8 - q11
-+// offset table in r7 and r5
-+// output in q0 - q3
-+// clobbers q12 - q15
-+.macro edge_w64_body
-+ diff32 q12, q13, q0, q1, q0, q1, q4, q5
-+ diff32 q0, q1, q14, q15, q8, q9, q4, q5
-+
-+ vadd.s8 q0, q12 //diff0 + diff1
-+ vadd.s8 q1, q13
-+
-+ diff32 q14, q15, q2, q3, q2, q3, q6, q7
-+ diff32 q2, q3, q12, q13, q10, q11, q6, q7
-+
-+ vadd.s8 q2, q14
-+ vadd.s8 q3, q15
-+ table64
-+.endm
-+
- .macro init_edge_64
- push {r4-r5}
- ldr r12, [sp, #8] // height
-@@ -334,38 +334,23 @@ function ff_hevc_sao_edge_eo3_w64_neon_8, export=1
- bx lr
- endfunc
-
--// inputs:
--// a in q0, q1
--// c in q2, q3
--// b in q8, q9
--// offset table in d31
--// clobbered registers q0, q1, q10, q11, q12, q13
--// output q0, q1
--.macro edge_w32_body
-- vcgt.u8 q12, q2, q0 // c > a -> -1 , otherwise 0
-- vcgt.u8 q0, q0, q2 // a > c -> -1 , otherwise 0
-- vcgt.u8 q13, q3, q1
-- vcgt.u8 q1, q1, q3
--
-- vsub.s8 q12, q0, q12 // diff0
-- vcgt.u8 q0, q2, q8 // c > b
-- vsub.s8 q13, q1, q13 // diff0 part 2
--
-- vcgt.u8 q10, q8, q2 // b > c
-- vcgt.u8 q1, q3, q9
-- vcgt.u8 q11, q9, q3
--
-- vsub.s8 q0, q10, q0 // diff1
--
-- vmov.s8 q10, #2 // 2 to all elements
-- vsub.s8 q1, q11, q1 // diff1 part 2
-- vadd.s8 q0, q12 //diff0 + diff1
-- vadd.s8 q1, q13
-+.macro init_edge_32
-+ ldr r12, [sp, #4] // sao_offset_val_table
-+ vld1.32 {d31}, [r12]
-+ ldr r12, [sp] // height
-+.endm
-
-- vadd.s8 q0, q10
-- vadd.s8 q1, q10
-+.macro diff out0, tmp0, in0, in1
-+ vcgt.u8 \out0, \in1, \in0 // c > a -> -1 , otherwise 0
-+ vcgt.u8 \tmp0, \in0, \in1 // a > c -> -1 , otherwise 0
-+ vsub.s8 \out0, \tmp0, \out0 // diff0
-+.endm
-
-- vmov.u8 q10, #128
-+.macro table32
-+ vmov.s8 q10, #2
-+ vadd.s8 q0, q10
-+ vadd.s8 q1, q10
-+ vmov.s8 q10, #128
- vtbl.8 d0, {d31}, d0
- vadd.s8 q11, q2, q10
- vtbl.8 d1, {d31}, d1
-@@ -373,56 +358,68 @@ endfunc
- vtbl.8 d2, {d31}, d2
- vqadd.s8 q11, q0
- vtbl.8 d3, {d31}, d3
-- vqadd.s8 q12, q1
-- vsub.s8 q0, q11, q10
-- vsub.s8 q1, q12, q10
-+ vqadd.s8 q12, q1
-+ vsub.s8 q0, q11, q10
-+ vsub.s8 q1, q12, q10
- vst1.8 {q0-q1}, [r0, :128], r2
- .endm
-
--.macro init_edge_32
-- ldr r12, [sp, #4] // sao_offset_val_table
-- vld1.32 {d31}, [r12]
-- ldr r12, [sp] // height
--.endm
--
- function ff_hevc_sao_edge_eo0_w32_neon_8, export=1
- init_edge_32
-- sub r1, #4 // load 4 extra bytes
-+ vpush {q4-q7}
-+ sub r1, #4
- 1: subs r12, #1
-- vld1.32 d3[1], [r1]!
-- vld1.8 {q2-q3}, [r1, :128]! // c
-- vld1.32 d20[0], [r1], r3
-- sub r1, #36
-+ vld1.8 {q13-q14}, [r1]!
-+ vld1.32 d30, [r1], r3
-+ sub r1, #32
- // a
-- vext.8 q0, q1, q2, #15
-- vext.8 q1, q2, q3, #15
-- // b
-- vext.8 q8, q2, q3, #1
-- vext.8 q9, q3, q10, #1
-- edge_w32_body
-+ vext.8 q0, q13, q14, #3
-+ vext.8 q1, q14, q15, #3
-+ vshr.u64 d24, d30, #24
-+ // c
-+ vext.8 q2, q13, q14, #4
-+ vext.8 q3, q14, q15, #4
-+ vshr.u64 d16, d30, #32
-+ // diff0
-+ diff32 q13, q14, q4, q5, q0, q1, q2, q3
-+ diff d18, d25, d24, d16
-+ // -diff1
-+ vext.s8 q0, q13, q14, #1
-+ vext.s8 q1, q14, q9, #1
-+
-+ vsub.s8 q0, q13, q0 //diff0 + diff1
-+ vsub.s8 q1, q14, q1
-+ table32
- bne 1b
-+ vpop {q4-q7}
-+
- bx lr
- endfunc
-
- function ff_hevc_sao_edge_eo1_w32_neon_8, export=1
- init_edge_32
-+ vpush {q4-q7}
- // load a
- sub r1, r3
- vld1.8 {q0-q1}, [r1, :128], r3
- // load c
- vld1.8 {q2-q3}, [r1, :128], r3
-+ diff32 q12, q13, q0, q1, q0, q1, q2, q3 // CMP ( c, a )
- 1: subs r12, #1
- // load b
- vld1.8 {q8-q9}, [r1, :128], r3
-- edge_w32_body
-- // inputs for next loop iteration
-- // a
-- vmov.64 q0, q2
-- vmov.64 q1, q3
-+ diff32 q4, q5, q10, q11, q8, q9, q2, q3 // CMP ( c, b )
-+ vadd.s8 q0, q4, q12 //diff0 + diff1
-+ vadd.s8 q1, q5, q13
-+ table32
-+ // CMP ( c, a )
-+ vneg.s8 q12, q4
-+ vneg.s8 q13, q5
- // c
- vmov.64 q2, q8
- vmov.64 q3, q9
- bne 1b
-+ vpop {q4-q7}
- bx lr
- endfunc
-
-@@ -452,7 +449,11 @@ function ff_hevc_sao_edge_eo2_w32_neon_8, export=1
- vext.8 q6, q10, q11, #8
- vext.8 q7, q11, q12, #8
- vext.8 q5, q10, q11, #7
-- edge_w32_body
-+ diff32 q12, q13, q0, q1, q0, q1, q2, q3
-+ diff32 q0, q1, q10, q11, q8, q9, q2, q3
-+ vadd.s8 q0, q12 //diff0 + diff1
-+ vadd.s8 q1, q13
-+ table32
- // inputs for next loop iteration
- // a
- vmov.8 q0, q4
-@@ -487,7 +488,14 @@ function ff_hevc_sao_edge_eo3_w32_neon_8, export=1
- vext.8 q8, q10, q11, #7
- vext.8 q9, q11, q12, #7
- vext.8 q14, q12, q10, #7
-- edge_w32_body
-+
-+ diff32 q12, q13, q0, q1, q0, q1, q2, q3
-+ diff32 q0, q1, q10, q11, q8, q9, q2, q3
-+
-+ vadd.s8 q0, q12 //diff0 + diff1
-+ vadd.s8 q1, q13
-+ table32
-+
- // inputs for next loop iteration
- // a
- vext.8 q0, q2, q3, #1
---
-2.5.0
-
-From 5a8f38083c6d9afec5029408c8680b2676752035 Mon Sep 17 00:00:00 2001
+From 4c05fa1631b5e8839a7763417c5220291308c707 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 28 Apr 2015 16:18:40 +0100
Subject: [PATCH 01/68] Added display output
@@ -3814,7 +8,7 @@ Subject: [PATCH 01/68] Added display output
1 file changed, 159 insertions(+)
diff --git a/ffmpeg.c b/ffmpeg.c
-index ce54374..026ffa9 100644
+index a5ec3c3..8828f48 100644
--- a/ffmpeg.c
+++ b/ffmpeg.c
@@ -23,6 +23,11 @@
@@ -3829,7 +23,7 @@ index ce54374..026ffa9 100644
#include "config.h"
#include
#include
-@@ -69,6 +74,20 @@
+@@ -66,6 +71,20 @@
# include "libavfilter/buffersrc.h"
# include "libavfilter/buffersink.h"
@@ -3850,7 +44,7 @@ index ce54374..026ffa9 100644
#if HAVE_SYS_RESOURCE_H
#include
#include
-@@ -161,6 +180,134 @@ static int restore_tty;
+@@ -158,6 +177,134 @@ static int restore_tty;
static void free_input_threads(void);
#endif
@@ -3985,7 +179,7 @@ index ce54374..026ffa9 100644
/* sub2video hack:
Convert subtitles to video with alpha to insert them in filter graphs.
This is a temporary solution until libavfilter gets real subtitles support.
-@@ -582,6 +729,10 @@ static void ffmpeg_cleanup(int ret)
+@@ -581,6 +728,10 @@ static void ffmpeg_cleanup(int ret)
}
term_exit();
ffmpeg_exited = 1;
@@ -3996,7 +190,7 @@ index ce54374..026ffa9 100644
}
void remove_avoptions(AVDictionary **a, AVDictionary *b)
-@@ -965,6 +1116,14 @@ static void do_video_out(AVFormatContext *s,
+@@ -928,6 +1079,14 @@ static void do_video_out(AVFormatContext *s,
int frame_size = 0;
InputStream *ist = NULL;
AVFilterContext *filter = ost->filter->filter;
@@ -4015,7 +209,7 @@ index ce54374..026ffa9 100644
2.5.0
-From a72c0e18e722b541d4bb10f1f5c966f95eccbec1 Mon Sep 17 00:00:00 2001
+From 90f7867ad638d03e8d1a9902990dfd7edd13fe0d Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 29 Apr 2015 16:49:43 +0100
Subject: [PATCH 02/68] Split transform and intra prediction into commands
@@ -4027,10 +221,10 @@ Subject: [PATCH 02/68] Split transform and intra prediction into commands
3 files changed, 191 insertions(+), 1 deletion(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 5f77761..5566ace 100644
+index 203f90a..2eebd31 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -918,6 +918,25 @@ static int hls_cross_component_pred(HEVCContext *s, int idx) {
+@@ -920,6 +920,25 @@ static int hls_cross_component_pred(HEVCContext *s, int idx) {
return 0;
}
@@ -4056,7 +250,7 @@ index 5f77761..5566ace 100644
static int hls_transform_unit(HEVCContext *s, int x0, int y0,
int xBase, int yBase, int cb_xBase, int cb_yBase,
int log2_cb_size, int log2_trafo_size,
-@@ -930,8 +949,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -932,8 +951,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
if (lc->cu.pred_mode == MODE_INTRA) {
int trafo_size = 1 << log2_trafo_size;
ff_hevc_set_neighbour_available(s, x0, y0, trafo_size, trafo_size);
@@ -4069,7 +263,7 @@ index 5f77761..5566ace 100644
}
if (cbf_luma || cbf_cb[0] || cbf_cr[0] ||
-@@ -1017,7 +1039,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1019,7 +1041,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
if (lc->cu.pred_mode == MODE_INTRA) {
ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v);
@@ -4081,7 +275,7 @@ index 5f77761..5566ace 100644
}
if (cbf_cb[i])
ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c),
-@@ -1046,7 +1072,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1048,7 +1074,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
if (lc->cu.pred_mode == MODE_INTRA) {
ff_hevc_set_neighbour_available(s, x0, y0 + (i << log2_trafo_size_c), trafo_size_h, trafo_size_v);
@@ -4093,7 +287,7 @@ index 5f77761..5566ace 100644
}
if (cbf_cr[i])
ff_hevc_hls_residual_coding(s, x0, y0 + (i << log2_trafo_size_c),
-@@ -1075,7 +1105,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1077,7 +1107,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
if (lc->cu.pred_mode == MODE_INTRA) {
ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size),
trafo_size_h, trafo_size_v);
@@ -4105,7 +299,7 @@ index 5f77761..5566ace 100644
}
if (cbf_cb[i])
ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size),
-@@ -1085,7 +1119,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1087,7 +1121,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
if (lc->cu.pred_mode == MODE_INTRA) {
ff_hevc_set_neighbour_available(s, xBase, yBase + (i << log2_trafo_size),
trafo_size_h, trafo_size_v);
@@ -4117,7 +311,7 @@ index 5f77761..5566ace 100644
}
if (cbf_cr[i])
ff_hevc_hls_residual_coding(s, xBase, yBase + (i << log2_trafo_size),
-@@ -1097,26 +1135,46 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1099,26 +1137,46 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
int trafo_size_h = 1 << (log2_trafo_size_c + s->ps.sps->hshift[1]);
int trafo_size_v = 1 << (log2_trafo_size_c + s->ps.sps->vshift[1]);
ff_hevc_set_neighbour_available(s, x0, y0, trafo_size_h, trafo_size_v);
@@ -4164,7 +358,7 @@ index 5f77761..5566ace 100644
}
}
}
-@@ -2291,6 +2349,31 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
+@@ -2293,6 +2351,31 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
lc->ctb_up_left_flag = ((x_ctb > 0) && (y_ctb > 0) && (ctb_addr_in_slice-1 >= s->ps.sps->ctb_width) && (s->ps.pps->tile_id[ctb_addr_ts] == s->ps.pps->tile_id[s->ps.pps->ctb_addr_rs_to_ts[ctb_addr_rs-1 - s->ps.sps->ctb_width]]));
}
@@ -4196,7 +390,7 @@ index 5f77761..5566ace 100644
static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
{
HEVCContext *s = avctxt->priv_data;
-@@ -2300,6 +2383,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2302,6 +2385,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
int y_ctb = 0;
int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
@@ -4207,7 +401,7 @@ index 5f77761..5566ace 100644
if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) {
av_log(s->avctx, AV_LOG_ERROR, "Impossible initial tile.\n");
return AVERROR_INVALIDDATA;
-@@ -2329,6 +2416,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2331,6 +2418,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
s->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag;
more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
@@ -4217,7 +411,7 @@ index 5f77761..5566ace 100644
if (more_data < 0) {
s->tab_slice_address[ctb_addr_rs] = -1;
return more_data;
-@@ -2374,6 +2464,10 @@ static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *input_ctb_row, int
+@@ -2376,6 +2466,10 @@ static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *input_ctb_row, int
s = s1->sList[self_id];
lc = s->HEVClc;
@@ -4228,7 +422,7 @@ index 5f77761..5566ace 100644
if(ctb_row) {
ret = init_get_bits8(&lc->gb, s->data + s->sh.offset[ctb_row - 1], s->sh.size[ctb_row - 1]);
-@@ -2998,6 +3092,13 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3064,6 +3158,13 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->cabac_state);
@@ -4242,7 +436,7 @@ index 5f77761..5566ace 100644
for (i = 0; i < 3; i++) {
av_freep(&s->sao_pixel_buffer_h[i]);
av_freep(&s->sao_pixel_buffer_v[i]);
-@@ -3057,6 +3158,22 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3123,6 +3224,22 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->HEVClcList[0] = s->HEVClc;
s->sList[0] = s;
@@ -4266,7 +460,7 @@ index 5f77761..5566ace 100644
if (!s->cabac_state)
goto fail;
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index d84e661..aa66b00 100644
+index c91f815..71174af 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -23,6 +23,9 @@
@@ -4378,7 +572,7 @@ index d1bef83..c0fdfad 100644
2.5.0
-From f4cf5194f103463ebd84eb36f571be06ca2aa49d Mon Sep 17 00:00:00 2001
+From 18fe64824d85a2ac9832bd5b600db8e52b5581fe Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 30 Apr 2015 15:23:22 +0100
Subject: [PATCH 03/68] Added simple VPU test code
@@ -4409,12 +603,12 @@ Subject: [PATCH 03/68] Added simple VPU test code
create mode 100644 libavcodec/rpi_user_vcsm.h
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
-index 5088304..54e14b4 100644
+index f6a4fbb..0fd6767 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
-@@ -4,6 +4,10 @@ NAME = avcodec
-
+@@ -5,6 +5,10 @@ NAME = avcodec
HEADERS = avcodec.h \
+ avdct.h \
avfft.h \
+ rpi_qpu.h \
+ rpi_shader.h \
@@ -4422,8 +616,8 @@ index 5088304..54e14b4 100644
+ rpi_hevc_transform.h \
dv_profile.h \
d3d11va.h \
- dxva2.h \
-@@ -35,6 +39,9 @@ OBJS = allcodecs.o \
+ dirac.h \
+@@ -39,6 +43,9 @@ OBJS = allcodecs.o \
resample.o \
resample2.o \
utils.o \
@@ -4434,12 +628,12 @@ index 5088304..54e14b4 100644
xiph.o \
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 5566ace..e58a3d0 100644
+index 2eebd31..681e9fd 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -39,6 +39,10 @@
- #include "golomb.h"
+@@ -41,6 +41,10 @@
#include "hevc.h"
+ #include "profiles.h"
+#ifdef RPI
+#include "rpi_qpu.h"
@@ -4448,7 +642,7 @@ index 5566ace..e58a3d0 100644
const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 };
/**
-@@ -2417,7 +2421,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2419,7 +2423,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
#ifdef RPI
@@ -4459,7 +653,7 @@ index 5566ace..e58a3d0 100644
#endif
if (more_data < 0) {
s->tab_slice_address[ctb_addr_rs] = -1;
-@@ -3172,6 +3178,31 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3238,6 +3244,31 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
if (!s->coeffs_buf)
goto fail;
s->enable_rpi = 0;
@@ -8600,7 +4794,7 @@ index 0000000..fbebbbe
2.5.0
-From 603cf327694d2f986538f13e6b8a1d92b2a9e0b2 Mon Sep 17 00:00:00 2001
+From 9018000735949ecb6640187dd2571753881edcfa Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Sat, 2 May 2015 21:15:37 +0100
Subject: [PATCH 04/68] First working version with uncached memory
@@ -8618,10 +4812,10 @@ Subject: [PATCH 04/68] First working version with uncached memory
9 files changed, 736 insertions(+), 46 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index e58a3d0..4aacb60 100644
+index 681e9fd..79678ea 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -43,6 +43,8 @@
+@@ -45,6 +45,8 @@
#include "rpi_qpu.h"
#endif
@@ -8630,7 +4824,7 @@ index e58a3d0..4aacb60 100644
const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12] = 4, [16] = 5, [24] = 6, [32] = 7, [48] = 8, [64] = 9 };
/**
-@@ -1066,11 +1068,15 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1068,11 +1070,15 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
for (i = 0; i < (size * size); i++) {
coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
}
@@ -8646,7 +4840,7 @@ index e58a3d0..4aacb60 100644
hls_cross_component_pred(s, 1);
}
for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
-@@ -1099,6 +1105,8 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1101,6 +1107,8 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
for (i = 0; i < (size * size); i++) {
coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
}
@@ -8655,7 +4849,7 @@ index e58a3d0..4aacb60 100644
s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride);
}
}
-@@ -1396,6 +1404,10 @@ static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+@@ -1398,6 +1406,10 @@ static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
(s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
int idx = ff_hevc_pel_weight[block_w];
@@ -8666,7 +4860,7 @@ index e58a3d0..4aacb60 100644
x_off += mv->x >> 2;
y_off += mv->y >> 2;
src += y_off * srcstride + (x_off * (1 << s->ps.sps->pixel_shift));
-@@ -1466,6 +1478,10 @@ static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+@@ -1468,6 +1480,10 @@ static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
uint8_t *src0 = ref0->data[0] + y_off0 * src0stride + (int)((unsigned)x_off0 << s->ps.sps->pixel_shift);
uint8_t *src1 = ref1->data[0] + y_off1 * src1stride + (int)((unsigned)x_off1 << s->ps.sps->pixel_shift);
@@ -8677,7 +4871,7 @@ index e58a3d0..4aacb60 100644
if (x_off0 < QPEL_EXTRA_BEFORE || y_off0 < QPEL_EXTRA_AFTER ||
x_off0 >= pic_width - block_w - QPEL_EXTRA_AFTER ||
y_off0 >= pic_height - block_h - QPEL_EXTRA_AFTER) {
-@@ -1551,6 +1567,10 @@ static void chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
+@@ -1553,6 +1569,10 @@ static void chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
intptr_t _mx = mx << (1 - hshift);
intptr_t _my = my << (1 - vshift);
@@ -8688,7 +4882,7 @@ index e58a3d0..4aacb60 100644
x_off += mv->x >> (2 + hshift);
y_off += mv->y >> (2 + vshift);
src0 += y_off * srcstride + (x_off * (1 << s->ps.sps->pixel_shift));
-@@ -1615,6 +1635,10 @@ static void chroma_mc_bi(HEVCContext *s, uint8_t *dst0, ptrdiff_t dststride, AVF
+@@ -1617,6 +1637,10 @@ static void chroma_mc_bi(HEVCContext *s, uint8_t *dst0, ptrdiff_t dststride, AVF
int hshift = s->ps.sps->hshift[1];
int vshift = s->ps.sps->vshift[1];
@@ -8699,7 +4893,7 @@ index e58a3d0..4aacb60 100644
intptr_t mx0 = av_mod_uintp2(mv0->x, 2 + hshift);
intptr_t my0 = av_mod_uintp2(mv0->y, 2 + vshift);
intptr_t mx1 = av_mod_uintp2(mv1->x, 2 + hshift);
-@@ -2354,6 +2378,22 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
+@@ -2356,6 +2380,22 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
}
#ifdef RPI
@@ -8722,7 +4916,7 @@ index e58a3d0..4aacb60 100644
static void rpi_execute_pred_cmds(HEVCContext *s)
{
int i;
-@@ -2374,7 +2414,6 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
+@@ -2376,7 +2416,6 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
}
}
s->num_pred_cmds = 0;
@@ -8730,7 +4924,7 @@ index e58a3d0..4aacb60 100644
}
#endif
-@@ -2421,7 +2460,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2423,7 +2462,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
#ifdef RPI
@@ -8740,7 +4934,7 @@ index e58a3d0..4aacb60 100644
rpi_execute_pred_cmds(s);
}
#endif
-@@ -3102,7 +3142,9 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3168,7 +3208,9 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->unif_mv_cmds);
av_freep(&s->unif_xfm_cmds);
av_freep(&s->univ_pred_cmds);
@@ -8751,7 +4945,7 @@ index e58a3d0..4aacb60 100644
#endif
for (i = 0; i < 3; i++) {
-@@ -3174,13 +3216,16 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3240,13 +3282,16 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->univ_pred_cmds = av_mallocz(sizeof(HEVCPredCmd)*RPI_MAX_PRED_CMDS);
if (!s->univ_pred_cmds)
goto fail;
@@ -8772,7 +4966,7 @@ index e58a3d0..4aacb60 100644
GPU_MEM_PTR_T p;
int err = gpu_malloc_cached(16, &p);
short *q = (short *)p.arm;
-@@ -3201,7 +3246,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3267,7 +3312,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
printf(")\n");
gpu_free(&p);
goto fail; // Early out
@@ -8782,7 +4976,7 @@ index e58a3d0..4aacb60 100644
#endif
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index aa66b00..f201817 100644
+index 71174af..1e4c34c 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -39,6 +39,11 @@
@@ -9791,7 +5985,7 @@ index 4e3c35c..814fc3c 100644
2.5.0
-From 1f1b223bd911a88726aa2c2f56334b15b421d7fa Mon Sep 17 00:00:00 2001
+From 4732d45788d56c44bda51c0cb12be912df89dab7 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 5 May 2015 09:41:23 +0100
Subject: [PATCH 05/68] Fixed deblocking
@@ -9801,10 +5995,10 @@ Subject: [PATCH 05/68] Fixed deblocking
1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 4aacb60..94fdda6 100644
+index 79678ea..862f915 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2387,8 +2387,9 @@ static void rpi_execute_transform(HEVCContext *s)
+@@ -2389,8 +2389,9 @@ static void rpi_execute_transform(HEVCContext *s)
// s->hevcdsp.idct[4-2](coeffs, 16);
//}
@@ -9815,7 +6009,7 @@ index 4aacb60..94fdda6 100644
for(i=0;i<4;i++)
s->num_coeffs[i] = 0;
-@@ -2427,6 +2428,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2429,6 +2430,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
#ifdef RPI
@@ -9823,7 +6017,7 @@ index 4aacb60..94fdda6 100644
s->enable_rpi = 1; // TODO this should depend on cross component and frame width etc.
#endif
-@@ -2460,9 +2462,17 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2462,9 +2464,17 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
#ifdef RPI
@@ -9842,7 +6036,7 @@ index 4aacb60..94fdda6 100644
}
#endif
if (more_data < 0) {
-@@ -2473,6 +2483,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2475,6 +2485,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
ctb_addr_ts++;
ff_hevc_save_states(s, ctb_addr_ts);
@@ -9853,7 +6047,7 @@ index 4aacb60..94fdda6 100644
ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size);
}
-@@ -3217,7 +3231,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3283,7 +3297,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
if (!s->univ_pred_cmds)
goto fail;
for(i = 0; i < 4; i++) {
@@ -9866,7 +6060,7 @@ index 4aacb60..94fdda6 100644
2.5.0
-From a32f8972fedc38dcf887f8f2899e8843efd6324a Mon Sep 17 00:00:00 2001
+From ddb4cf90d99f2e213de85244cd8e751570d794a8 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 5 May 2015 11:32:30 +0100
Subject: [PATCH 06/68] Added 32x32 transform
@@ -9880,10 +6074,10 @@ Subject: [PATCH 06/68] Added 32x32 transform
5 files changed, 148 insertions(+), 170 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 94fdda6..fbbd30f 100644
+index 862f915..fe71e03 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2387,9 +2387,11 @@ static void rpi_execute_transform(HEVCContext *s)
+@@ -2389,9 +2389,11 @@ static void rpi_execute_transform(HEVCContext *s)
// s->hevcdsp.idct[4-2](coeffs, 16);
//}
@@ -10591,7 +6785,7 @@ index d720546..12ad5fb 100644
2.5.0
-From 223fee0c814602a2aa5611c21fe052e6b6e063c1 Mon Sep 17 00:00:00 2001
+From cb4444b27d7e1d38d42375f52cd3741c2ebbe4ec Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 5 May 2015 16:57:03 +0100
Subject: [PATCH 07/68] Clear coefficients in advance
@@ -10605,10 +6799,10 @@ Subject: [PATCH 07/68] Clear coefficients in advance
5 files changed, 168 insertions(+), 40 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index fbbd30f..12e66a6 100644
+index fe71e03..8b93ca2 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -41,6 +41,8 @@
+@@ -43,6 +43,8 @@
#ifdef RPI
#include "rpi_qpu.h"
@@ -10617,7 +6811,7 @@ index fbbd30f..12e66a6 100644
#endif
// #define DISABLE_MC
-@@ -59,6 +61,20 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -61,6 +63,20 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
/* free everything allocated by pic_arrays_init() */
static void pic_arrays_free(HEVCContext *s)
{
@@ -10638,7 +6832,7 @@ index fbbd30f..12e66a6 100644
av_freep(&s->sao);
av_freep(&s->deblock);
-@@ -95,6 +111,28 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -97,6 +113,28 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
int ctb_count = sps->ctb_width * sps->ctb_height;
int min_pu_size = sps->min_pu_width * sps->min_pu_height;
@@ -10667,7 +6861,7 @@ index fbbd30f..12e66a6 100644
s->bs_width = (width >> 2) + 1;
s->bs_height = (height >> 2) + 1;
-@@ -2387,11 +2425,10 @@ static void rpi_execute_transform(HEVCContext *s)
+@@ -2389,11 +2427,10 @@ static void rpi_execute_transform(HEVCContext *s)
// s->hevcdsp.idct[4-2](coeffs, 16);
//}
@@ -10683,7 +6877,7 @@ index fbbd30f..12e66a6 100644
for(i=0;i<4;i++)
s->num_coeffs[i] = 0;
-@@ -2413,7 +2450,9 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
+@@ -2415,7 +2452,9 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
lc->na.cand_up_right = (cmd->na >> 0) & 1;
s->hpc.intra_pred[cmd->size - 2](s, cmd->x, cmd->y, cmd->c_idx);
} else {
@@ -10693,7 +6887,7 @@ index fbbd30f..12e66a6 100644
}
}
s->num_pred_cmds = 0;
-@@ -3158,10 +3197,18 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3224,10 +3263,18 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->unif_mv_cmds);
av_freep(&s->unif_xfm_cmds);
av_freep(&s->univ_pred_cmds);
@@ -10714,7 +6908,7 @@ index fbbd30f..12e66a6 100644
for (i = 0; i < 3; i++) {
av_freep(&s->sao_pixel_buffer_h[i]);
-@@ -3209,6 +3256,16 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3275,6 +3322,16 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
return 0;
}
@@ -10731,7 +6925,7 @@ index fbbd30f..12e66a6 100644
static av_cold int hevc_init_context(AVCodecContext *avctx)
{
HEVCContext *s = avctx->priv_data;
-@@ -3232,37 +3289,35 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3298,37 +3355,35 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->univ_pred_cmds = av_mallocz(sizeof(HEVCPredCmd)*RPI_MAX_PRED_CMDS);
if (!s->univ_pred_cmds)
goto fail;
@@ -10798,7 +6992,7 @@ index fbbd30f..12e66a6 100644
#endif
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index f201817..ca7c2aa 100644
+index 1e4c34c..e240b5c 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -887,8 +887,12 @@ typedef struct HEVCContext {
@@ -10943,7 +7137,7 @@ index afdb32a..fd159bc 100644
2.5.0
-From dffd0d9fc1ada2b61c61c73cba53538e564ced02 Mon Sep 17 00:00:00 2001
+From 3328a46c648542e5281088576dffac413de7a19d Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 6 May 2015 09:56:43 +0100
Subject: [PATCH 08/68] Prepared inter offload
@@ -10955,10 +7149,10 @@ Subject: [PATCH 08/68] Prepared inter offload
3 files changed, 137 insertions(+), 13 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 12e66a6..7453b63 100644
+index 8b93ca2..59f5d15 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -43,6 +43,8 @@
+@@ -45,6 +45,8 @@
#include "rpi_qpu.h"
// For some unknown reason, the code seems to crash if I do a late malloc
#define EARLY_MALLOC
@@ -10967,7 +7161,7 @@ index 12e66a6..7453b63 100644
#endif
// #define DISABLE_MC
-@@ -1427,6 +1429,95 @@ static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
+@@ -1429,6 +1431,95 @@ static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
* @param luma_offset additive offset applied to the luma prediction value
*/
@@ -11063,7 +7257,7 @@ index 12e66a6..7453b63 100644
static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
AVFrame *ref, const Mv *mv, int x_off, int y_off,
int block_w, int block_h, int luma_weight, int luma_offset)
-@@ -1492,7 +1583,7 @@ static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+@@ -1494,7 +1585,7 @@ static void luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
* @param mv1 motion vector1 (relative to block position) to get pixel data from
* @param current_mv current motion vector structure
*/
@@ -11072,7 +7266,7 @@ index 12e66a6..7453b63 100644
AVFrame *ref0, const Mv *mv0, int x_off, int y_off,
int block_w, int block_h, AVFrame *ref1, const Mv *mv1, struct MvField *current_mv)
{
-@@ -1874,16 +1965,16 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -1876,16 +1967,16 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int nPbW_c = nPbW >> s->ps.sps->hshift[1];
int nPbH_c = nPbH >> s->ps.sps->vshift[1];
@@ -11092,7 +7286,7 @@ index 12e66a6..7453b63 100644
0, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv,
s->sh.chroma_weight_l0[current_mv.ref_idx[0]][1], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][1]);
}
-@@ -1893,17 +1984,17 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -1895,17 +1986,17 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int nPbW_c = nPbW >> s->ps.sps->hshift[1];
int nPbH_c = nPbH >> s->ps.sps->vshift[1];
@@ -11113,7 +7307,7 @@ index 12e66a6..7453b63 100644
1, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv,
s->sh.chroma_weight_l1[current_mv.ref_idx[1]][1], s->sh.chroma_offset_l1[current_mv.ref_idx[1]][1]);
}
-@@ -1913,15 +2004,15 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -1915,15 +2006,15 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int nPbW_c = nPbW >> s->ps.sps->hshift[1];
int nPbH_c = nPbH >> s->ps.sps->vshift[1];
@@ -11132,7 +7326,7 @@ index 12e66a6..7453b63 100644
x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv, 1);
}
}
-@@ -2452,7 +2543,9 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
+@@ -2454,7 +2545,9 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
} else {
int trafo_size = 1 << cmd->size;
s->hevcdsp.transform_add[cmd->size-2](cmd->dst, cmd->buf, cmd->stride);
@@ -11142,7 +7336,7 @@ index 12e66a6..7453b63 100644
}
}
s->num_pred_cmds = 0;
-@@ -3309,6 +3402,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3375,6 +3468,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->coeffs_buf_arm[3] = coefs_per_row + s->coeffs_buf_arm[2];
s->coeffs_buf_vc[3] = sizeof(int16_t) * coefs_per_row + s->coeffs_buf_vc[2];
printf("Done\n");
@@ -11150,7 +7344,7 @@ index 12e66a6..7453b63 100644
//memset(s->coeffs_buf_arm[0],0, sizeof(int16_t) * coefs_per_row);
memclear16(s->coeffs_buf_arm[0], coefs_per_row);
//memset(s->coeffs_buf_arm[2],0, sizeof(int16_t) * coefs_per_row);
-@@ -3317,6 +3411,8 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3383,6 +3477,8 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
memclear16(s->coeffs_buf_arm[3], coefs_per_row);
#endif
@@ -11160,7 +7354,7 @@ index 12e66a6..7453b63 100644
#endif
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index ca7c2aa..8ef6f51 100644
+index e240b5c..a35ee4a 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -829,14 +829,39 @@ typedef struct HEVCLocalContext {
@@ -11225,7 +7419,7 @@ index a295d3e..f28759b 100644
2.5.0
-From fa1aa086848e704e43a90d09ddf35a5e7d99aae2 Mon Sep 17 00:00:00 2001
+From 191028358f7153c8598981673e6bd165acaa699d Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 6 May 2015 11:08:50 +0100
Subject: [PATCH 09/68] Inter prediction in separate pass
@@ -11236,10 +7430,10 @@ Subject: [PATCH 09/68] Inter prediction in separate pass
2 files changed, 77 insertions(+), 18 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 7453b63..83fdb57 100644
+index 59f5d15..f60709e 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -44,7 +44,7 @@
+@@ -46,7 +46,7 @@
// For some unknown reason, the code seems to crash if I do a late malloc
#define EARLY_MALLOC
// Move Inter prediction into separate pass
@@ -11248,7 +7442,7 @@ index 7453b63..83fdb57 100644
#endif
// #define DISABLE_MC
-@@ -1435,7 +1435,7 @@ static void rpi_luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+@@ -1437,7 +1437,7 @@ static void rpi_luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
AVFrame *ref, const Mv *mv, int x_off, int y_off,
int block_w, int block_h, int luma_weight, int luma_offset)
{
@@ -11257,7 +7451,7 @@ index 7453b63..83fdb57 100644
cmd->cmd = RPI_CMD_LUMA_UNI;
cmd->dst = dst;
cmd->dststride = dststride;
-@@ -1454,31 +1454,29 @@ static void rpi_luma_mc_bi(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+@@ -1456,31 +1456,29 @@ static void rpi_luma_mc_bi(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
AVFrame *ref0, const Mv *mv0, int x_off, int y_off,
int block_w, int block_h, AVFrame *ref1, const Mv *mv1, struct MvField *current_mv)
{
@@ -11296,7 +7490,7 @@ index 7453b63..83fdb57 100644
cmd->cmd = RPI_CMD_CHROMA_UNI;
cmd->dst = dst0;
cmd->dststride = dststride;
-@@ -1493,27 +1491,27 @@ static void chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
+@@ -1495,27 +1493,27 @@ static void chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
cmd->offset = chroma_offset;
}
@@ -11330,7 +7524,7 @@ index 7453b63..83fdb57 100644
#else
#define RPI_REDIRECT(fn) fn
#endif
-@@ -2541,7 +2539,9 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
+@@ -2543,7 +2541,9 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
lc->na.cand_up_right = (cmd->na >> 0) & 1;
s->hpc.intra_pred[cmd->size - 2](s, cmd->x, cmd->y, cmd->c_idx);
} else {
@@ -11340,7 +7534,7 @@ index 7453b63..83fdb57 100644
s->hevcdsp.transform_add[cmd->size-2](cmd->dst, cmd->buf, cmd->stride);
#ifdef RPI_PRECLEAR
memset(cmd->buf, 0, trafo_size * trafo_size * sizeof(int16_t)); // Clear coefficients here while they are in the cache
-@@ -2550,6 +2550,61 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
+@@ -2552,6 +2552,61 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
}
s->num_pred_cmds = 0;
}
@@ -11402,7 +7596,7 @@ index 7453b63..83fdb57 100644
#endif
static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
-@@ -2598,6 +2653,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2600,6 +2655,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#ifdef RPI
if (s->enable_rpi && x_ctb + ctb_size >= s->ps.sps->width) {
int x;
@@ -11411,7 +7605,7 @@ index 7453b63..83fdb57 100644
// Transform all blocks
rpi_execute_transform(s);
// Perform intra prediction and residual reconstruction
-@@ -3350,6 +3407,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3416,6 +3473,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
}
#ifdef RPI
@@ -11419,7 +7613,7 @@ index 7453b63..83fdb57 100644
static av_cold void memclear16(int16_t *p, int n)
{
vpu_execute_code( vpu_get_fn(), p, n, 0, 0, 0, 1);
-@@ -3358,6 +3416,7 @@ static av_cold void memclear16(int16_t *p, int n)
+@@ -3424,6 +3482,7 @@ static av_cold void memclear16(int16_t *p, int n)
// p[i] = 0;
}
#endif
@@ -11428,7 +7622,7 @@ index 7453b63..83fdb57 100644
static av_cold int hevc_init_context(AVCodecContext *avctx)
{
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 8ef6f51..8115d04 100644
+index a35ee4a..e3046a2 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -838,7 +838,7 @@ typedef struct HEVCLocalContext {
@@ -11444,7 +7638,7 @@ index 8ef6f51..8115d04 100644
2.5.0
-From eba684df008749ec0f5751ea2343198006682a1c Mon Sep 17 00:00:00 2001
+From cf8758aad96c2c71abd5f2feb8ff85b5ac191b60 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 6 May 2015 13:03:50 +0100
Subject: [PATCH 10/68] Added VPU thread
@@ -11457,10 +7651,10 @@ Subject: [PATCH 10/68] Added VPU thread
4 files changed, 133 insertions(+), 6 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 83fdb57..9b3edf2 100644
+index f60709e..7b0d951 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2516,8 +2516,10 @@ static void rpi_execute_transform(HEVCContext *s)
+@@ -2518,8 +2518,10 @@ static void rpi_execute_transform(HEVCContext *s)
gpu_cache_flush(&s->coeffs_buf_accelerated);
@@ -11472,7 +7666,7 @@ index 83fdb57..9b3edf2 100644
for(i=0;i<4;i++)
s->num_coeffs[i] = 0;
-@@ -2653,10 +2655,12 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2655,10 +2657,12 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#ifdef RPI
if (s->enable_rpi && x_ctb + ctb_size >= s->ps.sps->width) {
int x;
@@ -11487,7 +7681,7 @@ index 83fdb57..9b3edf2 100644
// Perform intra prediction and residual reconstruction
rpi_execute_pred_cmds(s);
// Perform deblocking for CTBs in this row
-@@ -3349,6 +3353,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3415,6 +3419,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->univ_pred_cmds);
#ifdef EARLY_MALLOC
@@ -11496,7 +7690,7 @@ index 83fdb57..9b3edf2 100644
gpu_free(&s->coeffs_buf_default);
s->coeffs_buf_arm[0] = 0;
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 8115d04..d5d3302 100644
+index e3046a2..89636e4 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -922,6 +922,7 @@ typedef struct HEVCContext {
@@ -11710,7 +7904,7 @@ index 814fc3c..3526fce 100644
2.5.0
-From d0d2aad80a05a30b2aca1d96dec3856c3a8d0ab9 Mon Sep 17 00:00:00 2001
+From 6914dc93330c6d8494712589cdaeb0927ce9118d Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 6 May 2015 15:03:37 +0100
Subject: [PATCH 11/68] Added different signal when tail moves
@@ -11773,7 +7967,7 @@ index 378dd74..d1c3e20 100644
2.5.0
-From dcb7e7134ab80be7971979f9893a83814d7ea962 Mon Sep 17 00:00:00 2001
+From 0f997c095dc4aa3ddc5818c8188803ade60c8c72 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 7 May 2015 08:57:11 +0100
Subject: [PATCH 12/68] Add option to test for gpu_idle
@@ -11784,10 +7978,10 @@ Subject: [PATCH 12/68] Add option to test for gpu_idle
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 9b3edf2..84cc636 100644
+index 7b0d951..b703200 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2514,7 +2514,6 @@ static void rpi_execute_transform(HEVCContext *s)
+@@ -2516,7 +2516,6 @@ static void rpi_execute_transform(HEVCContext *s)
// s->hevcdsp.idct[4-2](coeffs, 16);
//}
@@ -11795,7 +7989,7 @@ index 9b3edf2..84cc636 100644
gpu_cache_flush(&s->coeffs_buf_accelerated);
s->vpu_id = vpu_post_code( vpu_get_fn(), vpu_get_constants(), s->coeffs_buf_vc[2], s->num_coeffs[2] >> 8, s->coeffs_buf_vc[3], s->num_coeffs[3] >> 10, 0, &s->coeffs_buf_accelerated);
//vpu_execute_code( vpu_get_fn(), vpu_get_constants(), s->coeffs_buf_vc[2], s->num_coeffs[2] >> 8, s->coeffs_buf_vc[3], s->num_coeffs[3] >> 10, 0);
-@@ -2656,6 +2655,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2658,6 +2657,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
if (s->enable_rpi && x_ctb + ctb_size >= s->ps.sps->width) {
int x;
// Transform all blocks
@@ -11844,7 +8038,7 @@ index d1c3e20..85f49db 100644
2.5.0
-From 44d05d44ab3f81fec1ba75082ca2fe9340cb229c Mon Sep 17 00:00:00 2001
+From 3b7183a57c0936f10db7ae806db01ff6c977e095 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 7 May 2015 11:01:35 +0100
Subject: [PATCH 13/68] Added deblocking pass
@@ -11857,10 +8051,10 @@ Subject: [PATCH 13/68] Added deblocking pass
4 files changed, 39 insertions(+), 9 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 84cc636..57b0b63 100644
+index b703200..c12693b 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2505,6 +2505,17 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
+@@ -2507,6 +2507,17 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
}
#ifdef RPI
@@ -11878,7 +8072,7 @@ index 84cc636..57b0b63 100644
static void rpi_execute_transform(HEVCContext *s)
{
int i=2;
-@@ -2618,7 +2629,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2620,7 +2631,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
#ifdef RPI
@@ -11886,7 +8080,7 @@ index 84cc636..57b0b63 100644
s->enable_rpi = 1; // TODO this should depend on cross component and frame width etc.
#endif
-@@ -2652,7 +2662,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2654,7 +2664,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
#ifdef RPI
@@ -11898,7 +8092,7 @@ index 84cc636..57b0b63 100644
int x;
// Transform all blocks
//printf("%d %d %d : %d %d %d %d\n",s->poc, x_ctb, y_ctb, s->num_pred_cmds,s->num_mv_cmds,s->num_coeffs[2] >> 8,s->num_coeffs[3] >> 10);
-@@ -2665,10 +2678,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2667,10 +2680,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
// Perform intra prediction and residual reconstruction
rpi_execute_pred_cmds(s);
// Perform deblocking for CTBs in this row
@@ -11911,7 +8105,7 @@ index 84cc636..57b0b63 100644
}
#endif
if (more_data < 0) {
-@@ -2686,6 +2697,16 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2688,6 +2699,16 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
ff_hevc_hls_filters(s, x_ctb, y_ctb, ctb_size);
}
@@ -11929,7 +8123,7 @@ index 84cc636..57b0b63 100644
y_ctb + ctb_size >= s->ps.sps->height)
ff_hevc_hls_filter(s, x_ctb, y_ctb, ctb_size);
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index d5d3302..0b4c175 100644
+index 89636e4..1fcf8b9 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -834,6 +834,8 @@ typedef struct HEVCLocalContext {
@@ -11999,7 +8193,7 @@ index 85f49db..3b6dae7 100644
2.5.0
-From c4e1242d732ea2a14ce7cee5fb36e79bd2d8db35 Mon Sep 17 00:00:00 2001
+From 2e30016cc84d7b30f26bdeb1fbed69c3f495cded Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 7 May 2015 16:47:47 +0100
Subject: [PATCH 14/68] Added option to disable deblocking for non-ref frames
@@ -12040,7 +8234,7 @@ index ea0af91..2cdd621 100644
2.5.0
-From 8b2f1cd9b31d0c1ded0b00d4106b18897c1450e5 Mon Sep 17 00:00:00 2001
+From f5895e368e97fbd1ec04501b4be89a20f5cc5f29 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Mon, 11 May 2015 10:00:27 +0100
Subject: [PATCH 15/68] Moved buffers to VPU memory
@@ -12090,7 +8284,7 @@ index 2cdd621..e1b32d4 100644
}
}
diff --git a/libavcodec/utils.c b/libavcodec/utils.c
-index 892ddb9..df750a8 100644
+index f532824..b32047a 100644
--- a/libavcodec/utils.c
+++ b/libavcodec/utils.c
@@ -26,6 +26,12 @@
@@ -12106,7 +8300,7 @@ index 892ddb9..df750a8 100644
#include "libavutil/atomic.h"
#include "libavutil/attributes.h"
#include "libavutil/avassert.h"
-@@ -70,6 +76,10 @@
+@@ -63,6 +69,10 @@
#include "libavutil/ffversion.h"
const char av_codec_ffversion[] = "FFmpeg version " FFMPEG_VERSION;
@@ -12117,7 +8311,7 @@ index 892ddb9..df750a8 100644
#if HAVE_PTHREADS || HAVE_W32THREADS || HAVE_OS2THREADS
static int default_lockmgr_cb(void **arg, enum AVLockOp op)
{
-@@ -505,6 +515,47 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
+@@ -500,6 +510,47 @@ int avcodec_fill_audio_frame(AVFrame *frame, int nb_channels,
return ret;
}
@@ -12165,9 +8359,9 @@ index 892ddb9..df750a8 100644
static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
{
FramePool *pool = avctx->internal->pool;
-@@ -549,6 +600,14 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
+@@ -547,6 +598,14 @@ static int update_frame_pool(AVCodecContext *avctx, AVFrame *frame)
av_buffer_pool_uninit(&pool->pools[i]);
- pool->linesize[i] = picture.linesize[i];
+ pool->linesize[i] = linesize[i];
if (size[i]) {
+#ifdef RPI_GPU_BUFFERS
+ if (avctx->codec_id == AV_CODEC_ID_HEVC)
@@ -12212,7 +8406,7 @@ index b4399fd..0489002 100644
2.5.0
-From a51c8db9d5ed7d90ad83d7791dd8924911a88bd7 Mon Sep 17 00:00:00 2001
+From 969972796afe03290f6c2dd3251bce367b4c6847 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Mon, 11 May 2015 14:04:37 +0100
Subject: [PATCH 16/68] Prepared QPU execute code
@@ -12226,11 +8420,11 @@ Subject: [PATCH 16/68] Prepared QPU execute code
5 files changed, 276 insertions(+), 37 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 57b0b63..d055b47 100644
+index c12693b..3b10ea0 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -40,17 +40,45 @@
- #include "hevc.h"
+@@ -42,17 +42,45 @@
+ #include "profiles.h"
#ifdef RPI
-#include "rpi_qpu.h"
@@ -12280,7 +8474,7 @@ index 57b0b63..d055b47 100644
/**
* NOTE: Each function hls_foo correspond to the function foo in the
* specification (HLS stands for High Level Syntax).
-@@ -64,6 +92,7 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -66,6 +94,7 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
static void pic_arrays_free(HEVCContext *s)
{
#ifdef RPI
@@ -12288,7 +8482,7 @@ index 57b0b63..d055b47 100644
#ifdef EARLY_MALLOC
#else
printf("pic_arrays_free\n");
-@@ -1969,6 +1998,43 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -1971,6 +2000,43 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
s->sh.luma_offset_l0[current_mv.ref_idx[0]]);
if (s->ps.sps->chroma_format_idc) {
@@ -12332,7 +8526,7 @@ index 57b0b63..d055b47 100644
RPI_REDIRECT(chroma_mc_uni)(s, dst1, s->frame->linesize[1], ref0->frame->data[1], ref0->frame->linesize[1],
0, x0_c, y0_c, nPbW_c, nPbH_c, ¤t_mv,
s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]);
-@@ -2619,6 +2685,54 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
+@@ -2621,6 +2687,54 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
#endif
@@ -12387,7 +8581,7 @@ index 57b0b63..d055b47 100644
static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
{
HEVCContext *s = avctxt->priv_data;
-@@ -2645,6 +2759,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2647,6 +2761,10 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
}
}
@@ -12398,7 +8592,7 @@ index 57b0b63..d055b47 100644
while (more_data && ctb_addr_ts < s->ps.sps->ctb_size) {
int ctb_addr_rs = s->ps.pps->ctb_addr_ts_to_rs[ctb_addr_ts];
-@@ -2666,19 +2784,30 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2668,19 +2786,30 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
s->dblk_cmds[s->num_dblk_cmds][0] = x_ctb;
s->dblk_cmds[s->num_dblk_cmds++][1] = y_ctb;
if ( (((y_ctb + ctb_size)&63) == 0) && x_ctb + ctb_size >= s->ps.sps->width) {
@@ -12431,7 +8625,7 @@ index 57b0b63..d055b47 100644
}
}
#endif
-@@ -2699,6 +2828,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2701,6 +2830,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#ifdef RPI
if (s->enable_rpi && s->num_dblk_cmds) {
@@ -12441,7 +8635,7 @@ index 57b0b63..d055b47 100644
rpi_execute_transform(s);
rpi_execute_inter_cmds(s);
vpu_wait(s->vpu_id);
-@@ -3374,6 +3506,14 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3440,6 +3572,14 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->unif_xfm_cmds);
av_freep(&s->univ_pred_cmds);
@@ -12456,7 +8650,7 @@ index 57b0b63..d055b47 100644
#ifdef EARLY_MALLOC
printf("hevc_decode_free\n");
if (s->coeffs_buf_arm[0]) {
-@@ -3469,34 +3609,59 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3535,34 +3675,59 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
if (!s->univ_pred_cmds)
goto fail;
@@ -12541,7 +8735,7 @@ index 57b0b63..d055b47 100644
s->enable_rpi = 0;
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 0b4c175..8923a25 100644
+index 1fcf8b9..a19d3ab 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -41,7 +41,11 @@
@@ -12716,7 +8910,7 @@ index 3526fce..2b22d98 100644
2.5.0
-From 5fc9797992781c83747eadba05b8092cd85ebba7 Mon Sep 17 00:00:00 2001
+From 90df0cacf3bed37328d465a925e446c7d3e9583b Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 13 May 2015 11:47:23 +0100
Subject: [PATCH 17/68] Drafted chroma interpolation on QPUs
@@ -12732,10 +8926,10 @@ Subject: [PATCH 17/68] Drafted chroma interpolation on QPUs
7 files changed, 149 insertions(+), 50 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index d055b47..7897fdd 100644
+index 3b10ea0..a5e1524 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -58,11 +58,11 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -60,11 +60,11 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
// The QPU code for UV blocks only works up to a block width of 8
#define RPI_CHROMA_BLOCK_WIDTH 8
@@ -12749,7 +8943,7 @@ index d055b47..7897fdd 100644
{ ENCODE_COEFFS( 0, 0, -2, 58), ENCODE_COEFFS( 10, -2, 0, 0 ) },
{ ENCODE_COEFFS( 0, 0, -4, 54), ENCODE_COEFFS( 16, -2, 0, 0 ) },
{ ENCODE_COEFFS( 0, 0, -6, 46), ENCODE_COEFFS( 28, -4, 0, 0 ) },
-@@ -2716,6 +2716,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2718,6 +2718,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
for(k=0;k<8;k++) {
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_EXIT); // Add exit command
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS+3] = qpu_get_fn(QPU_MC_SETUP); // A dummy texture location (maps to our code) - this is needed as the texture requests are pipelined
@@ -12758,7 +8952,7 @@ index d055b47..7897fdd 100644
s->u_mvs[8-1][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_INTERRUPT_EXIT8); // This QPU will signal interrupt when all others are done and have acquired a semaphore
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 8923a25..a0d4631 100644
+index a19d3ab..40470f5 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -44,7 +44,7 @@
@@ -13081,7 +9275,7 @@ index 6851e83..02fdcb2 100644
2.5.0
-From 41380ff18142eef6a80ffae43f0c3d810c9384d8 Mon Sep 17 00:00:00 2001
+From 552770488305e7574028fe760aa16d00c1020afa Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 13 May 2015 13:54:11 +0100
Subject: [PATCH 18/68] Fixed chroma inter prediction
@@ -13095,10 +9289,10 @@ Subject: [PATCH 18/68] Fixed chroma inter prediction
5 files changed, 617 insertions(+), 609 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 7897fdd..bcc831e 100644
+index a5e1524..d4d272a 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -55,9 +55,11 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -57,9 +57,11 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
#ifdef RPI_INTER_QPU
#define RPI_CHROMA_COMMAND_WORDS 12
@@ -13110,7 +9304,7 @@ index 7897fdd..bcc831e 100644
#define ENCODE_COEFFS(c0, c1, c2, c3) (((c0) & 0xff) | ((c1) & 0xff) << 8 | ((c2) & 0xff) << 16 | ((c3) & 0xff) << 24)
// TODO Chroma only needs 4 taps
-@@ -2011,7 +2013,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2013,7 +2015,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int x1_c = x0_c + (mv->x >> (2 + hshift));
int y1_c = y0_c + (mv->y >> (2 + hshift));
@@ -13120,7 +9314,7 @@ index 7897fdd..bcc831e 100644
uint32_t *u = s->u_mvs[chan & 7];
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
-@@ -2717,6 +2720,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2719,6 +2722,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_EXIT); // Add exit command
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS+3] = qpu_get_fn(QPU_MC_SETUP); // A dummy texture location (maps to our code) - this is needed as the texture requests are pipelined
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS+4] = qpu_get_fn(QPU_MC_SETUP); // Also need a dummy for V
@@ -13128,7 +9322,7 @@ index 7897fdd..bcc831e 100644
}
s->u_mvs[8-1][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_INTERRUPT_EXIT8); // This QPU will signal interrupt when all others are done and have acquired a semaphore
-@@ -3617,7 +3621,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3683,7 +3687,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
// Also add space for the startup command for each stream.
{
@@ -13138,7 +9332,7 @@ index 7897fdd..bcc831e 100644
gpu_malloc_uncached( 8 * uv_commands_per_qpu * sizeof(uint32_t), &s->unif_mvs_ptr );
s->unif_mvs = (uint32_t *) s->unif_mvs_ptr.arm; // TODO support this allocation in non EARLY_MALLOC
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index a0d4631..cae6659 100644
+index 40470f5..442516d 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -44,7 +44,7 @@
@@ -14501,7 +10695,7 @@ index 02fdcb2..4809e1d 100644
2.5.0
-From b558abbe8e70ebb5d75988e2cd21976474a2d4eb Mon Sep 17 00:00:00 2001
+From 436c31805d8a53ace0fea63976a464c0e2d2a93c Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 13 May 2015 14:37:32 +0100
Subject: [PATCH 19/68] Removed unused luma functions
@@ -14515,10 +10709,10 @@ Subject: [PATCH 19/68] Removed unused luma functions
5 files changed, 396 insertions(+), 1726 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index bcc831e..3967361 100644
+index d4d272a..b4a3707 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2718,8 +2718,8 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2720,8 +2720,8 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
return;
for(k=0;k<8;k++) {
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_EXIT); // Add exit command
@@ -16850,7 +13044,7 @@ index 4809e1d..cd7346d 100644
2.5.0
-From f91f17a1cce2b0f6996569ee7cccf0c9768afd87 Mon Sep 17 00:00:00 2001
+From b0d344c931394c7f734b12ab63b7067857f1a2b3 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 13 May 2015 14:54:25 +0100
Subject: [PATCH 20/68] Moved chroma P1 to QPUs
@@ -16860,10 +13054,10 @@ Subject: [PATCH 20/68] Moved chroma P1 to QPUs
1 file changed, 38 insertions(+)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 3967361..4dad0e0 100644
+index b4a3707..4e9ac54 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2057,6 +2057,44 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2059,6 +2059,44 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
s->sh.luma_offset_l1[current_mv.ref_idx[1]]);
if (s->ps.sps->chroma_format_idc) {
@@ -16912,7 +13106,7 @@ index 3967361..4dad0e0 100644
2.5.0
-From 36aba6ea897093f6528658e78bf4deeba7eeecd2 Mon Sep 17 00:00:00 2001
+From 9e0a56b87c843033556835e00b562a76fa806f6e Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 13 May 2015 15:13:47 +0100
Subject: [PATCH 21/68] Added B prediction - not quite right
@@ -16925,10 +13119,10 @@ Subject: [PATCH 21/68] Added B prediction - not quite right
4 files changed, 141 insertions(+), 79 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 4dad0e0..eee617d 100644
+index 4e9ac54..9a13fd4 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2114,6 +2114,64 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2116,6 +2116,64 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
ref1->frame, ¤t_mv.mv[1], ¤t_mv);
if (s->ps.sps->chroma_format_idc) {
@@ -17235,7 +13429,7 @@ index cd7346d..870437d2 100644
2.5.0
-From 5dec9ecc623e90c6e14b72a34a6bffdd2a005edb Mon Sep 17 00:00:00 2001
+From 9bd4040dfa0e8146dd0a9d7ca191f98078e0d400 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 08:15:55 +0100
Subject: [PATCH 22/68] Added flush for SAO
@@ -17246,10 +13440,10 @@ Subject: [PATCH 22/68] Added flush for SAO
2 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index eee617d..58da57d 100644
+index 9a13fd4..96b3568 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2890,7 +2890,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2892,7 +2892,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
rpi_execute_inter_qpu(s);
#endif
// Transform all blocks
@@ -17331,7 +13525,7 @@ index 9b6e26d..92a8271 100644
2.5.0
-From 015b41d06a02e23c7937f6c91c4270b2bc2e48c9 Mon Sep 17 00:00:00 2001
+From d9e8153a94d637578cd0cdb6a0b737957abb8b8f Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 09:17:28 +0100
Subject: [PATCH 23/68] Stopped using acceleration in unsupported cases
@@ -17342,10 +13536,10 @@ Subject: [PATCH 23/68] Stopped using acceleration in unsupported cases
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 58da57d..c59ee63 100644
+index 96b3568..b9ae06a 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -1139,15 +1139,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1141,15 +1141,11 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
for (i = 0; i < (size * size); i++) {
coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
}
@@ -17361,7 +13555,7 @@ index 58da57d..c59ee63 100644
hls_cross_component_pred(s, 1);
}
for (i = 0; i < (s->ps.sps->chroma_format_idc == 2 ? 2 : 1); i++) {
-@@ -1176,8 +1172,6 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
+@@ -1178,8 +1174,6 @@ static int hls_transform_unit(HEVCContext *s, int x0, int y0,
for (i = 0; i < (size * size); i++) {
coeffs[i] = ((lc->tu.res_scale_val * coeffs_y[i]) >> 3);
}
@@ -17370,7 +13564,7 @@ index 58da57d..c59ee63 100644
s->hevcdsp.transform_add[log2_trafo_size_c-2](dst, coeffs, stride);
}
}
-@@ -2844,7 +2838,13 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2846,7 +2840,13 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
#ifdef RPI
@@ -17405,7 +13599,7 @@ index f28759b..ca76cb0 100644
2.5.0
-From 3b96ec07ff377691a80df9b15de202fcff660599 Mon Sep 17 00:00:00 2001
+From 0e326aaea2fd684025bfbd676bb7fa6f08acca22 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 09:42:16 +0100
Subject: [PATCH 24/68] Split B prediction into two passes
@@ -17421,10 +13615,10 @@ Subject: [PATCH 24/68] Split B prediction into two passes
7 files changed, 531 insertions(+), 241 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index c59ee63..7e82602 100644
+index b9ae06a..3994f2e 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -3729,6 +3729,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3795,6 +3795,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
p += uv_commands_per_qpu;
}
s->mc_filter_uv = qpu_get_fn(QPU_MC_FILTER_UV);
@@ -17433,7 +13627,7 @@ index c59ee63..7e82602 100644
}
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index cae6659..3511982 100644
+index 442516d..d33ab74 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -943,6 +943,7 @@ typedef struct HEVCContext {
@@ -18347,7 +14541,7 @@ index 870437d2..635b894 100644
2.5.0
-From 6ddd4f127ca17be70a2e60a7b2ff127de89b559c Mon Sep 17 00:00:00 2001
+From 2949df95e5f5008ac156336d9089e7b3e9e67841 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 10:04:55 +0100
Subject: [PATCH 25/68] Switch to using 16bit temp buffers
@@ -18359,10 +14553,10 @@ Subject: [PATCH 25/68] Switch to using 16bit temp buffers
3 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 7e82602..753f85c 100644
+index 3994f2e..68cd237 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2134,7 +2134,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2136,7 +2136,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
uint32_t *u = s->u_mvs[chan & 7];
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
@@ -18432,7 +14626,7 @@ index 635b894..9577121 100644
2.5.0
-From b516e30ff4a9354497d3b6ecee77bfaeb69ca4d6 Mon Sep 17 00:00:00 2001
+From 7a3732950264ea60ac26aeca55d3ac269798d0c3 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 10:30:44 +0100
Subject: [PATCH 26/68] Corrected B prediction: matching md5 sum for hobbit50
@@ -19409,7 +15603,7 @@ index 9577121..562dc35 100644
2.5.0
-From 5a589f03af71ff87e50d46520ed652571357c9cc Mon Sep 17 00:00:00 2001
+From 7f612d9e21849e339ef0ad0e2e5d8a2acaad2552 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 10:55:07 +0100
Subject: [PATCH 27/68] P prediction uses 4 tap filters
@@ -19422,10 +15616,10 @@ Subject: [PATCH 27/68] P prediction uses 4 tap filters
4 files changed, 344 insertions(+), 390 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 753f85c..16f2200 100644
+index 68cd237..8984585 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -63,15 +63,15 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -65,15 +65,15 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
#define ENCODE_COEFFS(c0, c1, c2, c3) (((c0) & 0xff) | ((c1) & 0xff) << 8 | ((c2) & 0xff) << 16 | ((c3) & 0xff) << 24)
// TODO Chroma only needs 4 taps
@@ -19450,7 +15644,7 @@ index 753f85c..16f2200 100644
};
static uint32_t get_vc_address(AVBufferRef *bref) {
-@@ -2014,16 +2014,16 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2016,16 +2016,16 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
u++[-RPI_CHROMA_COMMAND_WORDS] = s->mc_filter_uv;
@@ -19471,7 +15665,7 @@ index 753f85c..16f2200 100644
*u++ = (get_vc_address(s->frame->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2071,16 +2071,16 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2073,16 +2073,16 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
u++[-RPI_CHROMA_COMMAND_WORDS] = s->mc_filter_uv;
@@ -19492,7 +15686,7 @@ index 753f85c..16f2200 100644
*u++ = (get_vc_address(s->frame->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2135,29 +2135,29 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2137,29 +2137,29 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
u++[-RPI_CHROMA_COMMAND_WORDS] = s->mc_filter_uv_b0;
@@ -20303,7 +16497,7 @@ index 562dc35..8e4f18f 100644
2.5.0
-From b267b33e74268586aacdcc31ca02c35aba69a230 Mon Sep 17 00:00:00 2001
+From b7f5bb6522a31aeb9e69f18f3b5cc9c73636685c Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 11:03:51 +0100
Subject: [PATCH 28/68] Optimised B0 pass
@@ -20873,7 +17067,7 @@ index 8e4f18f..faa5755 100644
2.5.0
-From 7941c95bd5e968d6e1ea0462cb27c475aa4ee5e1 Mon Sep 17 00:00:00 2001
+From 6e69afcdf13d39d3f108824ae4496df799f7a6bd Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 11:12:43 +0100
Subject: [PATCH 29/68] Optimised B pass
@@ -21218,7 +17412,7 @@ index faa5755..f38c926 100644
2.5.0
-From 3c9637fbe9311db205c5e3a1ab178771dab22856 Mon Sep 17 00:00:00 2001
+From 75ce019e80ff7f2234d56949c191413ab1d9ad7e Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 11:17:09 +0100
Subject: [PATCH 30/68] Used P delay slots more efficiently
@@ -21752,7 +17946,7 @@ index f38c926..02e95dd 100644
2.5.0
-From 07f733af90de9d5823f62c0b7276bb1c7187ec6f Mon Sep 17 00:00:00 2001
+From a92dda80bf8043b39fa85752d9a9592e90370d77 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 11:22:25 +0100
Subject: [PATCH 31/68] Improved use of delay slots
@@ -22386,7 +18580,7 @@ index 02e95dd..10f5113 100644
2.5.0
-From 29956c5549eb94e418c42e838d0bfceeb95730b0 Mon Sep 17 00:00:00 2001
+From 70bf426922557224722d0b6c3ca5d688b4e91f00 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 11:31:23 +0100
Subject: [PATCH 32/68] Avoid writeback of first B results
@@ -22698,7 +18892,7 @@ index 10f5113..e138c95 100644
2.5.0
-From c184ce179f16ca497ed003805193651fa3b30817 Mon Sep 17 00:00:00 2001
+From fb7061693c79444c178f700799776ffd736f3561 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 14 May 2015 11:36:24 +0100
Subject: [PATCH 33/68] Cutdown size of chroma prediction commands
@@ -22711,10 +18905,10 @@ Subject: [PATCH 33/68] Cutdown size of chroma prediction commands
4 files changed, 281 insertions(+), 302 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 16f2200..da81a54 100644
+index 8984585..c65af74 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -54,7 +54,7 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -56,7 +56,7 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
#ifdef RPI_INTER_QPU
@@ -22723,7 +18917,7 @@ index 16f2200..da81a54 100644
#define UV_COMMANDS_PER_QPU ((1 + (256*64*2)/(4*4)) * RPI_CHROMA_COMMAND_WORDS)
// The QPU code for UV blocks only works up to a block width of 8
#define RPI_CHROMA_BLOCK_WIDTH 8
-@@ -2019,11 +2019,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2021,11 +2021,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[1]);
u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[2]);
*u++ = ( (nPbW_cframe->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2078,9 +2075,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2080,9 +2077,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = ( (nPbW_csh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]
*u++ = rpi_filter_coefs[_mx][0];
@@ -22745,7 +18939,7 @@ index 16f2200..da81a54 100644
*u++ = (get_vc_address(s->frame->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2141,11 +2136,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2143,11 +2138,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[2]);
*u++ = ( (nPbW_cmc_filter_uv_b;
u++[-RPI_CHROMA_COMMAND_WORDS] = x2_c - 1 + start_x;
-@@ -2153,11 +2145,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2155,11 +2147,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[1]);
u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[2]);
*u++ = ( (nPbW_cframe->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2795,7 +2784,7 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2797,7 +2786,7 @@ static void rpi_inter_clear(HEVCContext *s)
*s->u_mvs[i]++ = pic_height;
*s->u_mvs[i]++ = s->frame->linesize[1];
*s->u_mvs[i]++ = s->frame->linesize[2];
@@ -23422,7 +19616,7 @@ index e138c95..d9ffcda 100644
2.5.0
-From 5edce4e2a69b82aceb72f331737b5b00bf3af912 Mon Sep 17 00:00:00 2001
+From 87ea97549920ec537d6bb03b6848be12b7b4e252 Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 14 May 2015 15:21:49 +0100
Subject: [PATCH 34/68] hevc: don't redirect when not rpi_enabled
@@ -23432,10 +19626,10 @@ Subject: [PATCH 34/68] hevc: don't redirect when not rpi_enabled
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index da81a54..60b3d97 100644
+index c65af74..e2f8a87 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -1455,7 +1455,7 @@ static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
+@@ -1457,7 +1457,7 @@ static int hls_pcm_sample(HEVCContext *s, int x0, int y0, int log2_cb_size)
*/
#ifdef RPI_INTER
@@ -23448,7 +19642,7 @@ index da81a54..60b3d97 100644
2.5.0
-From 86652e6a111a593a8c14c8eecaa7e26a068febcf Mon Sep 17 00:00:00 2001
+From d922347fd57c0320b6c6983a6c0b7c3200dae393 Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 14 May 2015 15:22:02 +0100
Subject: [PATCH 35/68] Use /dev/vcio for mailbox access
@@ -23474,7 +19668,7 @@ index 536896f..77a56dd 100644
2.5.0
-From 05eb83c2f257c17a02abc01a6be6ae9df2d8e653 Mon Sep 17 00:00:00 2001
+From 70688cd4e7a3bb073fe32a1dbdded4c4dfee3a42 Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 14 May 2015 15:25:25 +0100
Subject: [PATCH 36/68] Use vcsm for all memory allocations
@@ -23782,7 +19976,7 @@ index 60bf079..f62051f 100644
2.5.0
-From 72b441dc9a9965ce3e5812be87081ffae1e166de Mon Sep 17 00:00:00 2001
+From a98ba0c30ea93bdf25308e679ed5a38f09b63f9d Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 14 May 2015 15:43:17 +0100
Subject: [PATCH 37/68] Enable EARLY_MALLOC and fix sps access bug
@@ -23792,10 +19986,10 @@ Subject: [PATCH 37/68] Enable EARLY_MALLOC and fix sps access bug
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 60b3d97..eee22eb 100644
+index e2f8a87..61f6dfb 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -42,7 +42,7 @@
+@@ -44,7 +44,7 @@
#ifdef RPI
#include "rpi_qpu.h"
// For some unknown reason, the code seems to crash if I do a late malloc
@@ -23804,7 +19998,7 @@ index 60b3d97..eee22eb 100644
// Move Inter prediction into separate pass
#define RPI_INTER
#endif
-@@ -147,7 +147,8 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -149,7 +149,8 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
#ifdef RPI
#ifdef EARLY_MALLOC
#else
@@ -23818,7 +20012,7 @@ index 60b3d97..eee22eb 100644
2.5.0
-From 6a0001e44872f9333caf6c6e7e5046cd56a3a21a Mon Sep 17 00:00:00 2001
+From 3e7256195852455e030586a1945cccc3fc7eb44a Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 14 May 2015 16:40:51 +0100
Subject: [PATCH 38/68] Add copy of av_mod_uintp2 for use with stable ffmpeg
@@ -23828,10 +20022,10 @@ Subject: [PATCH 38/68] Add copy of av_mod_uintp2 for use with stable ffmpeg
1 file changed, 8 insertions(+)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index eee22eb..cfdf6c2 100644
+index 61f6dfb..d27c7f3 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -49,6 +49,14 @@
+@@ -51,6 +51,14 @@
// #define DISABLE_MC
@@ -23850,7 +20044,7 @@ index eee22eb..cfdf6c2 100644
2.5.0
-From 6fbc046c87e413d38c789e82f73dfece27a64ff4 Mon Sep 17 00:00:00 2001
+From ba9624fdc6073af3392753925bcb712dba984be8 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Mon, 18 May 2015 11:11:02 +0100
Subject: [PATCH 39/68] Added support for weighted prediction in P frames
@@ -23863,10 +20057,10 @@ Subject: [PATCH 39/68] Added support for weighted prediction in P frames
4 files changed, 384 insertions(+), 285 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index cfdf6c2..0906ac2 100644
+index d27c7f3..98f8461 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -62,7 +62,7 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -64,7 +64,7 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
#ifdef RPI_INTER_QPU
@@ -23875,7 +20069,7 @@ index cfdf6c2..0906ac2 100644
#define UV_COMMANDS_PER_QPU ((1 + (256*64*2)/(4*4)) * RPI_CHROMA_COMMAND_WORDS)
// The QPU code for UV blocks only works up to a block width of 8
#define RPI_CHROMA_BLOCK_WIDTH 8
-@@ -2018,6 +2018,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2020,6 +2020,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int y1_c = y0_c + (mv->y >> (2 + hshift));
//int chan = x0>>8; // Allocate commands for the first 256 luma pixels across to the first QPU. This is optimised for images around 1920 width
int chan = x0>>8;
@@ -23884,7 +20078,7 @@ index cfdf6c2..0906ac2 100644
uint32_t *u = s->u_mvs[chan & 7];
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
-@@ -2030,6 +2032,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2032,6 +2034,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = ( (nPbW_cframe->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2072,6 +2081,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2074,6 +2083,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int y1_c = y0_c + (mv->y >> (2 + hshift));
//int chan = x0>>8; // Allocate commands for the first 256 luma pixels across to the first QPU. This is optimised for images around 1920 width
int chan = x0>>8;
@@ -23907,7 +20101,7 @@ index cfdf6c2..0906ac2 100644
uint32_t *u = s->u_mvs[chan & 7];
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
-@@ -2085,6 +2096,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2087,6 +2098,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
// TODO chroma weight and offset... s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]
*u++ = rpi_filter_coefs[_mx][0];
*u++ = rpi_filter_coefs[_my][0];
@@ -23921,7 +20115,7 @@ index cfdf6c2..0906ac2 100644
*u++ = (get_vc_address(s->frame->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2146,6 +2164,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2148,6 +2166,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = ( (nPbW_cmc_filter_uv_b;
-@@ -2156,6 +2175,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2158,6 +2177,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = ( (nPbW_cframe->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
-@@ -2782,6 +2802,9 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2784,6 +2804,9 @@ static void rpi_inter_clear(HEVCContext *s)
int i;
int pic_width = s->ps.sps->width >> s->ps.sps->hshift[1];
int pic_height = s->ps.sps->height >> s->ps.sps->vshift[1];
@@ -23947,7 +20141,7 @@ index cfdf6c2..0906ac2 100644
for(i=0;i<8;i++) {
s->u_mvs[i] = s->mvs_base[i];
*s->u_mvs[i]++ = 0;
-@@ -2793,6 +2816,13 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2795,6 +2818,13 @@ static void rpi_inter_clear(HEVCContext *s)
*s->u_mvs[i]++ = pic_height;
*s->u_mvs[i]++ = s->frame->linesize[1];
*s->u_mvs[i]++ = s->frame->linesize[2];
@@ -23961,7 +20155,7 @@ index cfdf6c2..0906ac2 100644
s->u_mvs[i] += 1; // Padding words
}
}
-@@ -2836,12 +2866,29 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2838,12 +2868,29 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
int ctb_addr_ts = s->ps.pps->ctb_addr_rs_to_ts[s->sh.slice_ctb_addr_rs];
#ifdef RPI
@@ -23992,7 +20186,7 @@ index cfdf6c2..0906ac2 100644
#endif
-@@ -2974,6 +3021,7 @@ static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *input_ctb_row, int
+@@ -2976,6 +3023,7 @@ static int hls_decode_entry_wpp(AVCodecContext *avctxt, void *input_ctb_row, int
#ifdef RPI
s->enable_rpi = 0;
@@ -24708,7 +20902,7 @@ index d9ffcda..97c4c02 100644
2.5.0
-From 21506fa30a0953a1caa467ea31f9ee2ebbdf5b79 Mon Sep 17 00:00:00 2001
+From b789dfe8032e13b13384315c6e40d59891c1d248 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 19 May 2015 08:43:30 +0100
Subject: [PATCH 40/68] Improved ordering of tasks
@@ -24718,10 +20912,10 @@ Subject: [PATCH 40/68] Improved ordering of tasks
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 0906ac2..1cc7900 100644
+index 98f8461..01898fd 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2930,15 +2930,15 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2932,15 +2932,15 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
s->dblk_cmds[s->num_dblk_cmds][0] = x_ctb;
s->dblk_cmds[s->num_dblk_cmds++][1] = y_ctb;
if ( (((y_ctb + ctb_size)&63) == 0) && x_ctb + ctb_size >= s->ps.sps->width) {
@@ -24745,7 +20939,7 @@ index 0906ac2..1cc7900 100644
2.5.0
-From c0437176b4799453c7731e8372c622c03d65db1b Mon Sep 17 00:00:00 2001
+From 005310ce2e038c9d9d8d6761b11718d218983975 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 20 May 2015 19:58:19 +0100
Subject: [PATCH 41/68] Drafted Luma inter prediction
@@ -25512,7 +21706,7 @@ index 97c4c02..9cfc0d9 100644
2.5.0
-From 3a5492970d13bf5ffe94898d59b3e882e7c8a1f5 Mon Sep 17 00:00:00 2001
+From e6e832826a1f27e07c1c9ff48e0690fe4a732dd3 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 20 May 2015 19:58:30 +0100
Subject: [PATCH 42/68] Added support for fast cache flush in deblocker
@@ -26773,7 +22967,7 @@ index fbebbbe..95e6de1 100644
2.5.0
-From 855a757b894c53ddeadeb94c74bd11d3b2fa1fd3 Mon Sep 17 00:00:00 2001
+From b3e42f057641ce7855d21f7c45f533df8c6c462d Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 20 May 2015 21:12:55 +0100
Subject: [PATCH 43/68] Added multi mailbox - not working
@@ -26787,10 +22981,10 @@ Subject: [PATCH 43/68] Added multi mailbox - not working
5 files changed, 147 insertions(+), 8 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 1cc7900..9bf0d28 100644
+index 01898fd..2ca783a 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -45,6 +45,11 @@
+@@ -47,6 +47,11 @@
//#define EARLY_MALLOC
// Move Inter prediction into separate pass
#define RPI_INTER
@@ -26802,7 +22996,7 @@ index 1cc7900..9bf0d28 100644
#endif
// #define DISABLE_MC
-@@ -2830,10 +2835,14 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2832,10 +2837,14 @@ static void rpi_inter_clear(HEVCContext *s)
static void rpi_execute_inter_qpu(HEVCContext *s)
{
int k;
@@ -26820,7 +23014,7 @@ index 1cc7900..9bf0d28 100644
for(k=0;k<8;k++) {
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_EXIT); // Add exit command
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS+3] = qpu_get_fn(QPU_MC_SETUP_UV); // A dummy texture location (maps to our code) - this is needed as the texture requests are pipelined
-@@ -2843,6 +2852,22 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2845,6 +2854,22 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
s->u_mvs[8-1][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_INTERRUPT_EXIT8); // This QPU will signal interrupt when all others are done and have acquired a semaphore
@@ -26843,7 +23037,7 @@ index 1cc7900..9bf0d28 100644
qpu_run_shader8(qpu_get_fn(QPU_MC_SETUP_UV),
(uint32_t)(unif_vc+(s->mvs_base[0 ] - (uint32_t*)s->unif_mvs_ptr.arm)),
(uint32_t)(unif_vc+(s->mvs_base[1 ] - (uint32_t*)s->unif_mvs_ptr.arm)),
-@@ -2853,6 +2878,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2855,6 +2880,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
(uint32_t)(unif_vc+(s->mvs_base[6 ] - (uint32_t*)s->unif_mvs_ptr.arm)),
(uint32_t)(unif_vc+(s->mvs_base[7 ] - (uint32_t*)s->unif_mvs_ptr.arm))
);
@@ -26851,7 +23045,7 @@ index 1cc7900..9bf0d28 100644
}
#endif
-@@ -2932,6 +2958,12 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2934,6 +2960,12 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
if ( (((y_ctb + ctb_size)&63) == 0) && x_ctb + ctb_size >= s->ps.sps->width) {
// Transform all blocks
// printf("%d %d %d : %d %d %d %d\n",s->poc, x_ctb, y_ctb, s->num_pred_cmds,s->num_mv_cmds,s->num_coeffs[2] >> 8,s->num_coeffs[3] >> 10);
@@ -26864,7 +23058,7 @@ index 1cc7900..9bf0d28 100644
rpi_execute_transform(s);
// Perform inter prediction
rpi_execute_inter_cmds(s);
-@@ -2939,6 +2971,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -2941,6 +2973,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
// Kick off inter prediction on QPUs
rpi_execute_inter_qpu(s);
#endif
@@ -27067,7 +23261,7 @@ index 88965e5..2f08f03 100644
2.5.0
-From e576989224bf22d2b945e9ded8b27bafe1bd5417 Mon Sep 17 00:00:00 2001
+From 71b8a1d77652d1cc298df2a1441ef3c913c2926b Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 21 May 2015 16:50:02 +0100
Subject: [PATCH 44/68] Pass qpu number in as uniform
@@ -27080,10 +23274,10 @@ Subject: [PATCH 44/68] Pass qpu number in as uniform
4 files changed, 657 insertions(+), 663 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 9bf0d28..25e1cbd 100644
+index 2ca783a..9605459 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -2821,6 +2821,7 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2823,6 +2823,7 @@ static void rpi_inter_clear(HEVCContext *s)
*s->u_mvs[i]++ = pic_height;
*s->u_mvs[i]++ = s->frame->linesize[1];
*s->u_mvs[i]++ = s->frame->linesize[2];
@@ -27091,7 +23285,7 @@ index 9bf0d28..25e1cbd 100644
if (weight_flag) {
*s->u_mvs[i]++ = 1 << (s->sh.chroma_log2_weight_denom + 6 - 1);
*s->u_mvs[i]++ = s->sh.chroma_log2_weight_denom + 6;
-@@ -2828,7 +2829,6 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2830,7 +2831,6 @@ static void rpi_inter_clear(HEVCContext *s)
*s->u_mvs[i]++ = 1 << 5;
*s->u_mvs[i]++ = 6;
}
@@ -28506,7 +24700,7 @@ index 9cfc0d9..a0b8e5a 100644
2.5.0
-From 2372b3e0797cfce130103357085d21baecb0d5a8 Mon Sep 17 00:00:00 2001
+From f9771d28dc02023eb3d051fb9104b6e051f0a58b Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Sat, 23 May 2015 13:20:21 +0100
Subject: [PATCH 45/68] Add new cache flushing routine
@@ -28520,10 +24714,10 @@ Subject: [PATCH 45/68] Add new cache flushing routine
5 files changed, 91 insertions(+), 61 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 25e1cbd..31bbf67 100644
+index 9605459..52293bf 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -3498,9 +3498,13 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
+@@ -3564,9 +3564,13 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
}
fail:
@@ -28761,7 +24955,7 @@ index 95e6de1..db41a4d 100644
2.5.0
-From 7ddf50b155ce8417e8b27735098b3651567f07e5 Mon Sep 17 00:00:00 2001
+From b91ec9a8437e65c59dddf323de875e62ee227403 Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Sat, 23 May 2015 21:10:10 +0100
Subject: [PATCH 46/68] Fix multi mailbox extra transform call
@@ -28771,10 +24965,10 @@ Subject: [PATCH 46/68] Fix multi mailbox extra transform call
1 file changed, 2 insertions(+)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 31bbf67..f479707 100644
+index 52293bf..fa6d788 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -3011,7 +3011,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3013,7 +3013,9 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#ifdef RPI_INTER_QPU
rpi_execute_inter_qpu(s);
#endif
@@ -28788,7 +24982,7 @@ index 31bbf67..f479707 100644
2.5.0
-From 9d16a24e225841b0ba09006edcd052ac2ccaf335 Mon Sep 17 00:00:00 2001
+From 03bbcfdda2db59b9603018b1cf0ca340d9ffc088 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 27 May 2015 16:44:29 +0100
Subject: [PATCH 47/68] Added support for running luma prediction on QPUs
@@ -28805,10 +24999,10 @@ Subject: [PATCH 47/68] Added support for running luma prediction on QPUs
8 files changed, 1464 insertions(+), 1203 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index f479707..c6b619b 100644
+index fa6d788..11b9e60 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -50,6 +50,11 @@
+@@ -52,6 +52,11 @@
// Define RPI_MULTI_MAILBOX to use the updated mailbox that can launch both QPU and VPU
#define RPI_MULTI_MAILBOX
#endif
@@ -28820,7 +25014,7 @@ index f479707..c6b619b 100644
#endif
// #define DISABLE_MC
-@@ -72,6 +77,13 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -74,6 +79,13 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
// The QPU code for UV blocks only works up to a block width of 8
#define RPI_CHROMA_BLOCK_WIDTH 8
@@ -28834,7 +25028,7 @@ index f479707..c6b619b 100644
#define ENCODE_COEFFS(c0, c1, c2, c3) (((c0) & 0xff) | ((c1) & 0xff) << 8 | ((c2) & 0xff) << 16 | ((c3) & 0xff) << 24)
-@@ -2002,10 +2014,46 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2004,10 +2016,46 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int nPbW_c = nPbW >> s->ps.sps->hshift[1];
int nPbH_c = nPbH >> s->ps.sps->vshift[1];
@@ -28882,7 +25076,7 @@ index f479707..c6b619b 100644
if (s->ps.sps->chroma_format_idc) {
#ifdef RPI_INTER_QPU
-@@ -2065,10 +2113,47 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2067,10 +2115,47 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int nPbW_c = nPbW >> s->ps.sps->hshift[1];
int nPbH_c = nPbH >> s->ps.sps->vshift[1];
@@ -28931,7 +25125,7 @@ index f479707..c6b619b 100644
if (s->ps.sps->chroma_format_idc) {
#ifdef RPI_INTER_QPU
-@@ -2102,8 +2187,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2104,8 +2189,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = rpi_filter_coefs[_mx][0];
*u++ = rpi_filter_coefs[_my][0];
if (weight_flag) {
@@ -28942,7 +25136,7 @@ index f479707..c6b619b 100644
} else {
*u++ = 1; // Weight of 1 and offset of 0
*u++ = 1;
-@@ -2130,9 +2215,44 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2132,9 +2217,44 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int nPbW_c = nPbW >> s->ps.sps->hshift[1];
int nPbH_c = nPbH >> s->ps.sps->vshift[1];
@@ -28988,7 +25182,7 @@ index f479707..c6b619b 100644
if (s->ps.sps->chroma_format_idc) {
#ifdef RPI_INTER_QPU
-@@ -2821,7 +2941,6 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2823,7 +2943,6 @@ static void rpi_inter_clear(HEVCContext *s)
*s->u_mvs[i]++ = pic_height;
*s->u_mvs[i]++ = s->frame->linesize[1];
*s->u_mvs[i]++ = s->frame->linesize[2];
@@ -28996,7 +25190,7 @@ index f479707..c6b619b 100644
if (weight_flag) {
*s->u_mvs[i]++ = 1 << (s->sh.chroma_log2_weight_denom + 6 - 1);
*s->u_mvs[i]++ = s->sh.chroma_log2_weight_denom + 6;
-@@ -2829,7 +2948,31 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2831,7 +2950,31 @@ static void rpi_inter_clear(HEVCContext *s)
*s->u_mvs[i]++ = 1 << 5;
*s->u_mvs[i]++ = 6;
}
@@ -29028,7 +25222,7 @@ index f479707..c6b619b 100644
}
static void rpi_execute_inter_qpu(HEVCContext *s)
-@@ -2837,6 +2980,9 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2839,6 +2982,9 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
int k;
int i;
uint32_t *unif_vc = (uint32_t *)s->unif_mvs_ptr.vc;
@@ -29038,7 +25232,7 @@ index f479707..c6b619b 100644
if (s->sh.slice_type == I_SLICE) {
#ifdef RPI_MULTI_MAILBOX
rpi_execute_transform(s);
-@@ -2852,8 +2998,23 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2854,8 +3000,23 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
s->u_mvs[8-1][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_INTERRUPT_EXIT8); // This QPU will signal interrupt when all others are done and have acquired a semaphore
@@ -29062,7 +25256,7 @@ index f479707..c6b619b 100644
s->vpu_id = vpu_qpu_post_code( vpu_get_fn(), vpu_get_constants(), s->coeffs_buf_vc[2], s->num_coeffs[2] >> 8, s->coeffs_buf_vc[3], s->num_coeffs[3] >> 10, 0,
qpu_get_fn(QPU_MC_SETUP_UV),
(uint32_t)(unif_vc+(s->mvs_base[0 ] - (uint32_t*)s->unif_mvs_ptr.arm)),
-@@ -2863,7 +3024,27 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2865,7 +3026,27 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
(uint32_t)(unif_vc+(s->mvs_base[4 ] - (uint32_t*)s->unif_mvs_ptr.arm)),
(uint32_t)(unif_vc+(s->mvs_base[5 ] - (uint32_t*)s->unif_mvs_ptr.arm)),
(uint32_t)(unif_vc+(s->mvs_base[6 ] - (uint32_t*)s->unif_mvs_ptr.arm)),
@@ -29091,7 +25285,7 @@ index f479707..c6b619b 100644
);
for(i=0;i<4;i++)
s->num_coeffs[i] = 0;
-@@ -2879,6 +3060,8 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2881,6 +3062,8 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
(uint32_t)(unif_vc+(s->mvs_base[7 ] - (uint32_t*)s->unif_mvs_ptr.arm))
);
#endif
@@ -29100,7 +25294,7 @@ index f479707..c6b619b 100644
}
#endif
-@@ -3502,8 +3685,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
+@@ -3568,8 +3751,7 @@ static int decode_nal_units(HEVCContext *s, const uint8_t *buf, int length)
fail:
if (s->ref && s->threads_type == FF_THREAD_FRAME) {
#ifdef RPI_INTER_QPU
@@ -29110,7 +25304,7 @@ index f479707..c6b619b 100644
#endif
ff_thread_report_progress(&s->ref->tf, INT_MAX, 0);
}
-@@ -3690,7 +3872,6 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3756,7 +3938,6 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
#ifdef RPI
av_freep(&s->unif_mv_cmds);
@@ -29118,7 +25312,7 @@ index f479707..c6b619b 100644
av_freep(&s->univ_pred_cmds);
#ifdef RPI_INTER_QPU
-@@ -3699,7 +3880,12 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -3765,7 +3946,12 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
s->unif_mvs = 0;
}
#endif
@@ -29132,7 +25326,7 @@ index f479707..c6b619b 100644
#ifdef EARLY_MALLOC
printf("hevc_decode_free\n");
-@@ -3789,9 +3975,6 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3855,9 +4041,6 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->unif_mv_cmds = av_mallocz(sizeof(HEVCMvCmd)*RPI_MAX_MV_CMDS);
if (!s->unif_mv_cmds)
goto fail;
@@ -29142,7 +25336,7 @@ index f479707..c6b619b 100644
s->univ_pred_cmds = av_mallocz(sizeof(HEVCPredCmd)*RPI_MAX_PRED_CMDS);
if (!s->univ_pred_cmds)
goto fail;
-@@ -3805,7 +3988,11 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3871,7 +4054,11 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
{
int uv_commands_per_qpu = UV_COMMANDS_PER_QPU;
uint32_t *p;
@@ -29154,7 +25348,7 @@ index f479707..c6b619b 100644
s->unif_mvs = (uint32_t *) s->unif_mvs_ptr.arm; // TODO support this allocation in non EARLY_MALLOC
// Set up initial locations for uniform streams
-@@ -3820,6 +4007,28 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -3886,6 +4073,28 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
}
#endif
@@ -29184,7 +25378,7 @@ index f479707..c6b619b 100644
#ifdef EARLY_MALLOC
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 3511982..33dedf7 100644
+index d33ab74..a3668a2 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -43,9 +43,13 @@
@@ -29246,7 +25440,7 @@ index 3511982..33dedf7 100644
#endif
-@@ -1181,6 +1189,10 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+@@ -1192,6 +1200,10 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
int log2_trafo_size, enum ScanType scan_idx,
int c_idx);
@@ -32107,7 +28301,7 @@ index a0b8e5a..60d1ec2 100644
2.5.0
-From 2be17e0759404007c938bdd478e1e76445d9ecbe Mon Sep 17 00:00:00 2001
+From e5b20751b9a026e127ff0cdd8768b1d37ca5aa27 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 2 Jun 2015 10:58:25 +0100
Subject: [PATCH 48/68] Added option to simulate QPUs
@@ -32119,10 +28313,10 @@ Subject: [PATCH 48/68] Added option to simulate QPUs
3 files changed, 295 insertions(+), 23 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index c6b619b..7914afb 100644
+index 11b9e60..9be5276 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -54,6 +54,8 @@
+@@ -56,6 +56,8 @@
// Define RPI_CACHE_UNIF_MVS to write motion vector uniform stream to cached memory
// RPI_CACHE_UNIF_MVS doesn't seem to make much difference, so left undefined.
@@ -32131,7 +28325,7 @@ index c6b619b..7914afb 100644
#endif
-@@ -122,7 +124,6 @@ static void pic_arrays_free(HEVCContext *s)
+@@ -124,7 +126,6 @@ static void pic_arrays_free(HEVCContext *s)
#ifdef EARLY_MALLOC
#else
@@ -32139,7 +28333,7 @@ index c6b619b..7914afb 100644
if (s->coeffs_buf_arm[0]) {
gpu_free(&s->coeffs_buf_default);
s->coeffs_buf_arm[0] = 0;
-@@ -172,11 +173,9 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -174,11 +175,9 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
#ifdef RPI
#ifdef EARLY_MALLOC
#else
@@ -32152,7 +28346,7 @@ index c6b619b..7914afb 100644
gpu_malloc_cached(sizeof(int16_t) * coefs_per_row, &s->coeffs_buf_default);
s->coeffs_buf_arm[0] = (int16_t*) s->coeffs_buf_default.arm;
if (!s->coeffs_buf_arm[0])
-@@ -2975,6 +2974,274 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2977,6 +2976,274 @@ static void rpi_inter_clear(HEVCContext *s)
#endif
}
@@ -32427,7 +28621,7 @@ index c6b619b..7914afb 100644
static void rpi_execute_inter_qpu(HEVCContext *s)
{
int k;
-@@ -2993,7 +3260,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -2995,7 +3262,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_EXIT); // Add exit command
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS+3] = qpu_get_fn(QPU_MC_SETUP_UV); // A dummy texture location (maps to our code) - this is needed as the texture requests are pipelined
s->u_mvs[k][-RPI_CHROMA_COMMAND_WORDS+4] = qpu_get_fn(QPU_MC_SETUP_UV); // Also need a dummy for V
@@ -32436,7 +28630,7 @@ index c6b619b..7914afb 100644
}
s->u_mvs[8-1][-RPI_CHROMA_COMMAND_WORDS] = qpu_get_fn(QPU_MC_INTERRUPT_EXIT8); // This QPU will signal interrupt when all others are done and have acquired a semaphore
-@@ -3003,11 +3270,16 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3005,11 +3272,16 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
s->y_mvs[k][-RPI_LUMA_COMMAND_WORDS+1] = qpu_get_fn(QPU_MC_SETUP_UV); // A dummy texture location (maps to our code) - this is needed as the texture requests are pipelined
s->y_mvs[k][-RPI_LUMA_COMMAND_WORDS+3] = qpu_get_fn(QPU_MC_SETUP_UV); // Also need a dummy for second request
s->y_mvs[k][-RPI_LUMA_COMMAND_WORDS+8] = qpu_get_fn(QPU_MC_EXIT); // Add exit command
@@ -32454,7 +28648,7 @@ index c6b619b..7914afb 100644
#ifdef RPI_MULTI_MAILBOX
#ifdef RPI_CACHE_UNIF_MVS
-@@ -3088,7 +3360,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3090,7 +3362,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
&& s->ps.pps->num_tile_rows <= 1 && s->ps.pps->num_tile_columns <= 1;
#endif
@@ -32463,7 +28657,7 @@ index c6b619b..7914afb 100644
if (s->ps.pps->cross_component_prediction_enabled_flag)
printf("Cross component\n");
if (s->ps.pps->num_tile_rows > 1 || s->ps.pps->num_tile_columns > 1)
-@@ -3097,7 +3369,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3099,7 +3371,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
printf("Weighted P slice\n");
if (s->ps.pps->weighted_bipred_flag && s->sh.slice_type == B_SLICE)
printf("Weighted B slice\n");
@@ -32574,7 +28768,7 @@ index 60d1ec2..0686249 100644
2.5.0
-From 70805b593a428f11dcaf1e558214884601f6c44a Mon Sep 17 00:00:00 2001
+From 1c4e1f07dbed84272a36cd8c25cf9d40be5cfd7c Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 2 Jun 2015 13:17:50 +0100
Subject: [PATCH 49/68] Increased motion vector memory and fixed block size
@@ -32585,10 +28779,10 @@ Subject: [PATCH 49/68] Increased motion vector memory and fixed block size
1 file changed, 31 insertions(+), 19 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 7914afb..0d947ea 100644
+index 9be5276..c864ddb 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -81,11 +81,9 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -83,11 +83,9 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
// Split image of 2048 into parts 64 wide
// So some QPUs will have 3 blocks of 64 to do, and others 2 blocks for an image 2048 wide with 32 blocks across
@@ -32602,7 +28796,7 @@ index 7914afb..0d947ea 100644
#define ENCODE_COEFFS(c0, c1, c2, c3) (((c0) & 0xff) | ((c1) & 0xff) << 8 | ((c2) & 0xff) << 16 | ((c3) & 0xff) << 24)
-@@ -2029,11 +2027,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2031,11 +2029,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
uint32_t *y = s->y_mvs[chan % 12];
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=16) {
@@ -32617,7 +28811,7 @@ index 7914afb..0d947ea 100644
*y++ = my2_mx2_my_mx;
if (weight_flag) {
*y++ = (s->sh.luma_offset_l0[current_mv.ref_idx[reflist]] << 16) + (s->sh.luma_weight_l0[current_mv.ref_idx[reflist]] & 0xffff);
-@@ -2076,12 +2076,14 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2078,12 +2078,14 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
uint32_t *u = s->u_mvs[chan & 7];
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
@@ -32633,7 +28827,7 @@ index 7914afb..0d947ea 100644
*u++ = rpi_filter_coefs[_mx][0];
*u++ = rpi_filter_coefs[_my][0];
if (weight_flag) {
-@@ -2128,11 +2130,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2130,11 +2132,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
uint32_t *y = s->y_mvs[chan % 12];
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=16) {
@@ -32648,7 +28842,7 @@ index 7914afb..0d947ea 100644
*y++ = my2_mx2_my_mx;
if (weight_flag) {
*y++ = (s->sh.luma_offset_l0[current_mv.ref_idx[reflist]] << 16) + (s->sh.luma_weight_l0[current_mv.ref_idx[reflist]] & 0xffff);
-@@ -2176,12 +2180,14 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2178,12 +2182,14 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
uint32_t *u = s->u_mvs[chan & 7];
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
@@ -32664,7 +28858,7 @@ index 7914afb..0d947ea 100644
// TODO chroma weight and offset... s->sh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]
*u++ = rpi_filter_coefs[_mx][0];
*u++ = rpi_filter_coefs[_my][0];
-@@ -2233,11 +2239,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2235,11 +2241,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
uint32_t *y = s->y_mvs[chan % 12];
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=8) { // B blocks work 8 at a time
@@ -32679,7 +28873,7 @@ index 7914afb..0d947ea 100644
*y++ = my2_mx2_my_mx;
*y++ = 1; // B frame weighted prediction not supported
*y++ = (get_vc_address(s->frame->buf[0]) + x0 + start_x + (start_y + y0) * s->frame->linesize[0]);
-@@ -2280,12 +2288,14 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2282,12 +2290,14 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
uint32_t *u = s->u_mvs[chan & 7];
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
@@ -32695,7 +28889,7 @@ index 7914afb..0d947ea 100644
*u++ = rpi_filter_coefs[_mx][0];
*u++ = rpi_filter_coefs[_my][0];
u+=2; // Weights not supported in B slices
-@@ -2296,7 +2306,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2298,7 +2308,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
u++[-RPI_CHROMA_COMMAND_WORDS] = y2_c - 1 + start_y;
u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[1]);
u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[2]);
@@ -32704,7 +28898,7 @@ index 7914afb..0d947ea 100644
*u++ = rpi_filter_coefs[_mx2][0];
*u++ = rpi_filter_coefs[_my2][0];
u+=2; // Weights not supported in B slices
-@@ -3165,14 +3175,15 @@ static void rpi_simulate_inter_chroma(HEVCContext *s,uint32_t *p)
+@@ -3167,14 +3177,15 @@ static void rpi_simulate_inter_chroma(HEVCContext *s,uint32_t *p)
}
// mc_setup(y_x, ref_y_base, y2_x2, ref_y2_base, frame_width_height, pitch, dst_pitch, offset_shift, next_kernel)
@@ -32725,7 +28919,7 @@ index 7914afb..0d947ea 100644
uint8_t *ref_y_base;
uint8_t *ref_y2_base;
uint32_t frame_width_height = p[4];
-@@ -3202,13 +3213,15 @@ static void rpi_simulate_inter_luma(HEVCContext *s,uint32_t *p)
+@@ -3204,13 +3215,15 @@ static void rpi_simulate_inter_luma(HEVCContext *s,uint32_t *p)
uint8_t *this_dst = compute_arm_addr(s,p[7],0);
uint32_t width = width_height >> 16;
uint32_t height = (width_height << 16) >> 16;
@@ -32742,7 +28936,7 @@ index 7914afb..0d947ea 100644
}
else {
int32_t refa = filter8_luma(ref_y_base, x+x0, y+y0, pitch, my2_mx2_my_mx, 1, 0, 0, frame_width, frame_height);
-@@ -3235,7 +3248,7 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
+@@ -3237,7 +3250,7 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
}
for(i=0;i<12;i++)
{
@@ -32751,7 +28945,7 @@ index 7914afb..0d947ea 100644
}
}
-@@ -3277,7 +3290,6 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3279,7 +3292,6 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
#ifdef RPI_SIMULATE_QPUS
rpi_simulate_inter_qpu(s);
@@ -32763,7 +28957,7 @@ index 7914afb..0d947ea 100644
2.5.0
-From 1bd38623db52970590df65f4a7338d924c63a781 Mon Sep 17 00:00:00 2001
+From e6447ea51d299460471d5ac7e2fb6efe374574ee Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 2 Jun 2015 14:36:54 +0100
Subject: [PATCH 50/68] Added support for skip deblock
@@ -32775,10 +28969,10 @@ Subject: [PATCH 50/68] Added support for skip deblock
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 0d947ea..1812801 100644
+index c864ddb..7acd243 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -3384,6 +3384,11 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3386,6 +3386,11 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
}
#endif
@@ -32791,7 +28985,7 @@ index 0d947ea..1812801 100644
if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) {
av_log(s->avctx, AV_LOG_ERROR, "Impossible initial tile.\n");
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 33dedf7..aa4d218 100644
+index a3668a2..520d16f 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -916,6 +916,8 @@ typedef struct HEVCContext {
@@ -32844,7 +29038,7 @@ index 11629e4..14a0952 100644
2.5.0
-From 691cba7253bc997f6e8020542203c5733930d997 Mon Sep 17 00:00:00 2001
+From 0b1f5a86b7b99b237d1eae321ed4083365f4103b Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Tue, 2 Jun 2015 15:22:52 +0100
Subject: [PATCH 51/68] Added support for skip_frame
@@ -32854,10 +29048,10 @@ Subject: [PATCH 51/68] Added support for skip_frame
1 file changed, 10 insertions(+), 5 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 1812801..94ff677 100644
+index 7acd243..0324968 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -3384,11 +3384,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3386,11 +3386,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
}
#endif
@@ -32869,7 +29063,7 @@ index 1812801..94ff677 100644
if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) {
av_log(s->avctx, AV_LOG_ERROR, "Impossible initial tile.\n");
-@@ -3848,6 +3843,16 @@ static int decode_nal_unit(HEVCContext *s, const HEVCNAL *nal)
+@@ -3914,6 +3909,16 @@ static int decode_nal_unit(HEVCContext *s, const HEVCNAL *nal)
if (ret < 0)
return ret;
@@ -32890,7 +29084,7 @@ index 1812801..94ff677 100644
2.5.0
-From b489872a14709b7e04285e039dff80b75823eb72 Mon Sep 17 00:00:00 2001
+From 04e23231d9f7c40c6b6d124a048fac976f302a52 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 3 Jun 2015 09:15:38 +0100
Subject: [PATCH 52/68] Fixed cache flushing of luma when using old method
@@ -32916,7 +29110,7 @@ index 14a0952..b286bbf 100644
2.5.0
-From 6a4811cba68b1c27326300b37e43cdbad45ec45e Mon Sep 17 00:00:00 2001
+From 26eae6b28ba1027063a48258f47d4702ccba53cc Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 3 Jun 2015 11:37:27 +0100
Subject: [PATCH 53/68] Option to parallelise coefficient decode and inter
@@ -32930,10 +29124,10 @@ Subject: [PATCH 53/68] Option to parallelise coefficient decode and inter
4 files changed, 522 insertions(+), 270 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 94ff677..594340a 100644
+index 0324968..6f67872 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -41,8 +41,6 @@
+@@ -43,8 +43,6 @@
#ifdef RPI
#include "rpi_qpu.h"
@@ -32942,7 +29136,7 @@ index 94ff677..594340a 100644
// Move Inter prediction into separate pass
#define RPI_INTER
-@@ -56,6 +54,21 @@
+@@ -58,6 +56,21 @@
// Define RPI_SIMULATE_QPUS for debugging to run QPU code on the ARMs
//#define RPI_SIMULATE_QPUS
@@ -32964,7 +29158,7 @@ index 94ff677..594340a 100644
#endif
-@@ -103,6 +116,143 @@ static uint32_t get_vc_address(AVBufferRef *bref) {
+@@ -105,6 +118,143 @@ static uint32_t get_vc_address(AVBufferRef *bref) {
GPU_MEM_PTR_T *p = av_buffer_pool_opaque(bref);
return p->vc;
}
@@ -33108,7 +29302,7 @@ index 94ff677..594340a 100644
#endif
-@@ -119,19 +269,18 @@ static uint32_t get_vc_address(AVBufferRef *bref) {
+@@ -121,19 +271,18 @@ static uint32_t get_vc_address(AVBufferRef *bref) {
static void pic_arrays_free(HEVCContext *s)
{
#ifdef RPI
@@ -33138,7 +29332,7 @@ index 94ff677..594340a 100644
av_freep(&s->sao);
av_freep(&s->deblock);
-@@ -169,24 +318,26 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -171,24 +320,26 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
int min_pu_size = sps->min_pu_width * sps->min_pu_height;
#ifdef RPI
@@ -33180,7 +29374,7 @@ index 94ff677..594340a 100644
#endif
s->bs_width = (width >> 2) + 1;
-@@ -1023,7 +1174,7 @@ static void rpi_intra_pred(HEVCContext *s, int log2_trafo_size, int x0, int y0,
+@@ -1025,7 +1176,7 @@ static void rpi_intra_pred(HEVCContext *s, int log2_trafo_size, int x0, int y0,
{
if (s->enable_rpi) {
HEVCLocalContext *lc = s->HEVClc;
@@ -33189,7 +29383,7 @@ index 94ff677..594340a 100644
cmd->type = RPI_PRED_INTRA;
cmd->size = log2_trafo_size;
cmd->c_idx = c_idx;
-@@ -1483,7 +1634,7 @@ static void rpi_luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+@@ -1485,7 +1636,7 @@ static void rpi_luma_mc_uni(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
AVFrame *ref, const Mv *mv, int x_off, int y_off,
int block_w, int block_h, int luma_weight, int luma_offset)
{
@@ -33198,7 +29392,7 @@ index 94ff677..594340a 100644
cmd->cmd = RPI_CMD_LUMA_UNI;
cmd->dst = dst;
cmd->dststride = dststride;
-@@ -1502,7 +1653,7 @@ static void rpi_luma_mc_bi(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
+@@ -1504,7 +1655,7 @@ static void rpi_luma_mc_bi(HEVCContext *s, uint8_t *dst, ptrdiff_t dststride,
AVFrame *ref0, const Mv *mv0, int x_off, int y_off,
int block_w, int block_h, AVFrame *ref1, const Mv *mv1, struct MvField *current_mv)
{
@@ -33207,7 +29401,7 @@ index 94ff677..594340a 100644
cmd->cmd = RPI_CMD_LUMA_BI;
cmd->dst = dst;
cmd->dststride = dststride;
-@@ -1524,7 +1675,7 @@ static void rpi_chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
+@@ -1526,7 +1677,7 @@ static void rpi_chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
ptrdiff_t dststride, uint8_t *src0, ptrdiff_t srcstride, int reflist,
int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int chroma_weight, int chroma_offset)
{
@@ -33216,7 +29410,7 @@ index 94ff677..594340a 100644
cmd->cmd = RPI_CMD_CHROMA_UNI;
cmd->dst = dst0;
cmd->dststride = dststride;
-@@ -1542,7 +1693,7 @@ static void rpi_chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
+@@ -1544,7 +1695,7 @@ static void rpi_chroma_mc_uni(HEVCContext *s, uint8_t *dst0,
static void rpi_chroma_mc_bi(HEVCContext *s, uint8_t *dst0, ptrdiff_t dststride, AVFrame *ref0, AVFrame *ref1,
int x_off, int y_off, int block_w, int block_h, struct MvField *current_mv, int cidx)
{
@@ -33225,7 +29419,7 @@ index 94ff677..594340a 100644
cmd->cmd = RPI_CMD_CHROMA_BI+cidx;
cmd->dst = dst0;
cmd->dststride = dststride;
-@@ -2024,7 +2175,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2026,7 +2177,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int chan = x0>>6; // 64 wide blocks per QPU
int weight_flag = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
(s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
@@ -33234,7 +29428,7 @@ index 94ff677..594340a 100644
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=16) {
int bw = nPbW-start_x;
-@@ -2044,7 +2195,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2046,7 +2197,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter;
}
}
@@ -33243,7 +29437,7 @@ index 94ff677..594340a 100644
} else
#endif
{
-@@ -2073,7 +2224,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2075,7 +2226,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int weight_flag = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
(s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
@@ -33252,7 +29446,7 @@ index 94ff677..594340a 100644
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
int bw = nPbW_c-start_x;
-@@ -2097,7 +2248,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2099,7 +2250,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
}
@@ -33261,7 +29455,7 @@ index 94ff677..594340a 100644
return;
}
#endif
-@@ -2127,7 +2278,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2129,7 +2280,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int chan = x0>>6; // 64 wide blocks per QPU
int weight_flag = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
(s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
@@ -33270,7 +29464,7 @@ index 94ff677..594340a 100644
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=16) {
int bw = nPbW-start_x;
-@@ -2147,7 +2298,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2149,7 +2300,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter;
}
}
@@ -33279,7 +29473,7 @@ index 94ff677..594340a 100644
} else
#endif
-@@ -2177,7 +2328,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2179,7 +2330,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int weight_flag = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
(s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
@@ -33288,7 +29482,7 @@ index 94ff677..594340a 100644
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
int bw = nPbW_c-start_x;
-@@ -2202,7 +2353,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2204,7 +2355,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
}
@@ -33297,7 +29491,7 @@ index 94ff677..594340a 100644
return;
}
#endif
-@@ -2236,7 +2387,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2238,7 +2389,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int x2 = x0 + (mv2->x >> 2);
int y2 = y0 + (mv2->y >> 2);
int chan = x0>>6; // 64 wide blocks per QPU
@@ -33306,7 +29500,7 @@ index 94ff677..594340a 100644
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=8) { // B blocks work 8 at a time
int bw = nPbW-start_x;
-@@ -2252,7 +2403,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2254,7 +2405,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter_b;
}
}
@@ -33315,7 +29509,7 @@ index 94ff677..594340a 100644
} else
#endif
{
-@@ -2285,7 +2436,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2287,7 +2438,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int chan = x0>>8; // Allocate commands for the first 256 luma pixels across to the first QPU. This is optimised for images around 1920 width
@@ -33324,7 +29518,7 @@ index 94ff677..594340a 100644
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
int bw = nPbW_c-start_x;
-@@ -2314,7 +2465,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2316,7 +2467,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
}
@@ -33333,7 +29527,7 @@ index 94ff677..594340a 100644
return;
}
#endif
-@@ -2819,40 +2970,54 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
+@@ -2821,40 +2972,54 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
static void rpi_execute_dblk_cmds(HEVCContext *s)
{
int n;
@@ -33396,7 +29590,7 @@ index 94ff677..594340a 100644
if (cmd->type == RPI_PRED_INTRA) {
lc->tu.intra_pred_mode_c = lc->tu.intra_pred_mode = cmd->mode;
lc->na.cand_bottom_left = (cmd->na >> 4) & 1;
-@@ -2871,21 +3036,26 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
+@@ -2873,21 +3038,26 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
#endif
}
}
@@ -33427,7 +29621,7 @@ index 94ff677..594340a 100644
switch(cmd->cmd) {
case RPI_CMD_LUMA_UNI:
myref.data[0] = cmd->src;
-@@ -2925,7 +3095,28 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
+@@ -2927,7 +3097,28 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
break;
}
}
@@ -33457,7 +29651,7 @@ index 94ff677..594340a 100644
}
#endif
-@@ -2933,6 +3124,7 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
+@@ -2935,6 +3126,7 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
#ifdef RPI_INTER_QPU
static void rpi_inter_clear(HEVCContext *s)
{
@@ -33465,7 +29659,7 @@ index 94ff677..594340a 100644
int i;
int pic_width = s->ps.sps->width >> s->ps.sps->hshift[1];
int pic_height = s->ps.sps->height >> s->ps.sps->vshift[1];
-@@ -2940,51 +3132,50 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -2942,51 +3134,50 @@ static void rpi_inter_clear(HEVCContext *s)
(s->sh.slice_type == B_SLICE && s->ps.pps->weighted_bipred_flag);
for(i=0;i<8;i++) {
@@ -33543,7 +29737,7 @@ index 94ff677..594340a 100644
#ifdef RPI_SIMULATE_QPUS
static int32_t clipx(int x,int FRAME_WIDTH)
-@@ -3258,10 +3449,15 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
+@@ -3260,10 +3451,15 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
static void rpi_execute_inter_qpu(HEVCContext *s)
{
int k;
@@ -33561,7 +29755,7 @@ index 94ff677..594340a 100644
#endif
if (s->sh.slice_type == I_SLICE) {
#ifdef RPI_MULTI_MAILBOX
-@@ -3270,22 +3466,22 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3272,22 +3468,22 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
#endif
}
for(k=0;k<8;k++) {
@@ -33594,7 +29788,7 @@ index 94ff677..594340a 100644
#endif
#ifdef RPI_SIMULATE_QPUS
-@@ -3295,34 +3491,34 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3297,34 +3493,34 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
#ifdef RPI_MULTI_MAILBOX
#ifdef RPI_CACHE_UNIF_MVS
@@ -33652,7 +29846,7 @@ index 94ff677..594340a 100644
#else
0,
0,0,0,0,
-@@ -3331,17 +3527,17 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3333,17 +3529,17 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
#endif
);
for(i=0;i<4;i++)
@@ -33679,7 +29873,7 @@ index 94ff677..594340a 100644
);
#endif
-@@ -3398,6 +3594,11 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3400,6 +3596,11 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
}
}
@@ -33691,7 +29885,7 @@ index 94ff677..594340a 100644
#ifdef RPI_INTER_QPU
rpi_inter_clear(s);
#endif
-@@ -3418,46 +3619,42 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3420,46 +3621,42 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
s->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag;
more_data = hls_coding_quadtree(s, x_ctb, y_ctb, s->ps.sps->log2_ctb_size, 0);
@@ -33765,7 +29959,7 @@ index 94ff677..594340a 100644
if (more_data < 0) {
s->tab_slice_address[ctb_addr_rs] = -1;
return more_data;
-@@ -3474,18 +3671,21 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3476,18 +3673,21 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
}
#ifdef RPI
@@ -33797,7 +29991,7 @@ index 94ff677..594340a 100644
#endif
if (x_ctb + ctb_size >= s->ps.sps->width &&
-@@ -4153,6 +4353,48 @@ fail:
+@@ -4219,6 +4419,48 @@ fail:
return AVERROR(ENOMEM);
}
@@ -33846,7 +30040,7 @@ index 94ff677..594340a 100644
static av_cold int hevc_decode_free(AVCodecContext *avctx)
{
HEVCContext *s = avctx->priv_data;
-@@ -4165,33 +4407,29 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
+@@ -4231,33 +4473,29 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->cabac_state);
#ifdef RPI
@@ -33897,7 +30091,7 @@ index 94ff677..594340a 100644
#endif
for (i = 0; i < 3; i++) {
-@@ -4256,6 +4494,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -4322,6 +4560,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
{
HEVCContext *s = avctx->priv_data;
int i;
@@ -33905,7 +30099,7 @@ index 94ff677..594340a 100644
s->avctx = avctx;
-@@ -4266,12 +4505,14 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -4332,12 +4571,14 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->sList[0] = s;
#ifdef RPI
@@ -33926,7 +30120,7 @@ index 94ff677..594340a 100644
#ifdef RPI_INTER_QPU
// We divide the image into blocks 256 wide and 64 high
-@@ -4282,18 +4523,20 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -4348,18 +4589,20 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
{
int uv_commands_per_qpu = UV_COMMANDS_PER_QPU;
uint32_t *p;
@@ -33954,7 +30148,7 @@ index 94ff677..594340a 100644
}
s->mc_filter_uv = qpu_get_fn(QPU_MC_FILTER_UV);
s->mc_filter_uv_b0 = qpu_get_fn(QPU_MC_FILTER_UV_B0);
-@@ -4302,61 +4545,35 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
+@@ -4368,61 +4611,35 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
}
#endif
#ifdef RPI_LUMA_QPU
@@ -34029,7 +30223,7 @@ index 94ff677..594340a 100644
s->cabac_state = av_malloc(HEVC_CONTEXTS);
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index aa4d218..8d72344 100644
+index 520d16f..b540ca5 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -50,6 +50,12 @@
@@ -34218,7 +30412,7 @@ index 71c6d52..344e021 100644
2.5.0
-From e3604dee43bae2083ecea8b578da9878a7877f1f Mon Sep 17 00:00:00 2001
+From ec8c58875a457dcda45e8bbe1edc0efec41e4707 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 3 Jun 2015 13:43:48 +0100
Subject: [PATCH 54/68] Avoid lockup bug with RPI_WORKER enabled
@@ -34229,10 +30423,10 @@ Subject: [PATCH 54/68] Avoid lockup bug with RPI_WORKER enabled
2 files changed, 11 insertions(+), 12 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 594340a..323d5f9 100644
+index 6f67872..865f5ec 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -131,11 +131,11 @@ static uint32_t get_vc_address(AVBufferRef *bref) {
+@@ -133,11 +133,11 @@ static uint32_t get_vc_address(AVBufferRef *bref) {
static void worker_submit_job(HEVCContext *s)
{
LOG_ENTER
@@ -34247,7 +30441,7 @@ index 594340a..323d5f9 100644
LOG_EXIT
}
-@@ -143,11 +143,11 @@ static void worker_submit_job(HEVCContext *s)
+@@ -145,11 +145,11 @@ static void worker_submit_job(HEVCContext *s)
static void worker_complete_middle_job(HEVCContext *s)
{
LOG_ENTER
@@ -34263,7 +30457,7 @@ index 594340a..323d5f9 100644
LOG_EXIT
}
-@@ -155,11 +155,11 @@ static void worker_complete_middle_job(HEVCContext *s)
+@@ -157,11 +157,11 @@ static void worker_complete_middle_job(HEVCContext *s)
static void worker_complete_job(HEVCContext *s)
{
LOG_ENTER
@@ -34295,7 +30489,7 @@ index b9f773b..16e7ac3 100644
2.5.0
-From 38c4114cd6d6335dde5a4ba86f0f6e1a1529ad6a Mon Sep 17 00:00:00 2001
+From d9e7ab6809af47b65372b9fd99e2d519c3d44b10 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 3 Jun 2015 15:37:19 +0100
Subject: [PATCH 55/68] Added code to flush buffers at start of frame
@@ -34305,10 +30499,10 @@ Subject: [PATCH 55/68] Added code to flush buffers at start of frame
1 file changed, 72 insertions(+)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 323d5f9..aa72f97 100644
+index 865f5ec..3a94830 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -41,6 +41,7 @@
+@@ -43,6 +43,7 @@
#ifdef RPI
#include "rpi_qpu.h"
@@ -34316,7 +30510,7 @@ index 323d5f9..aa72f97 100644
// Move Inter prediction into separate pass
#define RPI_INTER
-@@ -3495,6 +3496,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3497,6 +3498,7 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
#else
gpu_cache_flush(&s->coeffs_buf_accelerated[job]);
#endif
@@ -34324,7 +30518,7 @@ index 323d5f9..aa72f97 100644
s->vpu_id = vpu_qpu_post_code( vpu_get_fn(), vpu_get_constants(), s->coeffs_buf_vc[job][2], s->num_coeffs[job][2] >> 8, s->coeffs_buf_vc[job][3], s->num_coeffs[job][3] >> 10, 0,
qpu_get_fn(QPU_MC_SETUP_UV),
(uint32_t)(unif_vc+(s->mvs_base[job][0 ] - (uint32_t*)s->unif_mvs_ptr[job].arm)),
-@@ -3545,6 +3547,71 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3547,6 +3549,71 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
}
#endif
@@ -34396,7 +30590,7 @@ index 323d5f9..aa72f97 100644
static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
{
HEVCContext *s = avctxt->priv_data;
-@@ -3579,8 +3646,12 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3581,8 +3648,12 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
printf("Weighted B slice\n");
}
@@ -34409,7 +30603,7 @@ index 323d5f9..aa72f97 100644
if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) {
av_log(s->avctx, AV_LOG_ERROR, "Impossible initial tile.\n");
return AVERROR_INVALIDDATA;
-@@ -3651,6 +3722,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3653,6 +3724,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
rpi_do_all_passes(s);
#endif
}
@@ -34421,7 +30615,7 @@ index 323d5f9..aa72f97 100644
2.5.0
-From b279851bb85b1fe15355603dcd53c3f1b6f06724 Mon Sep 17 00:00:00 2001
+From 2e0fc42393a67cc61d84311640d1e44b32f2bffb Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 3 Jun 2015 16:42:24 +0100
Subject: [PATCH 56/68] Reduce the amount that needs to be flushed
@@ -34431,10 +30625,10 @@ Subject: [PATCH 56/68] Reduce the amount that needs to be flushed
1 file changed, 11 insertions(+), 24 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index aa72f97..a2ba177 100644
+index 3a94830..3fcbc57 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -3556,7 +3556,7 @@ static void flush_buffer(AVBufferRef *bref) {
+@@ -3558,7 +3558,7 @@ static void flush_buffer(AVBufferRef *bref) {
static void flush_frame(HEVCContext *s,AVFrame *frame)
{
@@ -34443,7 +30637,7 @@ index aa72f97..a2ba177 100644
struct vcsm_user_clean_invalid_s iocache = {};
int n = s->ps.sps->height;
int curr_y = 0;
-@@ -3590,26 +3590,6 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
+@@ -3592,26 +3592,6 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
#endif
}
@@ -34470,7 +30664,7 @@ index aa72f97..a2ba177 100644
#endif
static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
-@@ -3645,9 +3625,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3647,9 +3627,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
if (s->ps.pps->weighted_bipred_flag && s->sh.slice_type == B_SLICE)
printf("Weighted B slice\n");
}
@@ -34480,7 +30674,7 @@ index aa72f97..a2ba177 100644
#endif
//printf("L0=%d L1=%d\n",s->sh.nb_refs[L1],s->sh.nb_refs[L1]);
-@@ -4053,6 +4030,11 @@ static int hevc_frame_start(HEVCContext *s)
+@@ -4119,6 +4096,11 @@ static int hevc_frame_start(HEVCContext *s)
if (!s->avctx->hwaccel)
ff_thread_finish_setup(s->avctx);
@@ -34492,7 +30686,7 @@ index aa72f97..a2ba177 100644
return 0;
fail:
-@@ -4254,6 +4236,11 @@ fail:
+@@ -4320,6 +4302,11 @@ fail:
ff_hevc_flush_buffer(s, &s->ref->tf, s->ps.sps->height);
#endif
ff_thread_report_progress(&s->ref->tf, INT_MAX, 0);
@@ -34508,7 +30702,7 @@ index aa72f97..a2ba177 100644
2.5.0
-From 7475c16d1b6b4ce94bb65f42bf3ae26969d4abf4 Mon Sep 17 00:00:00 2001
+From 0cc4754dcc1c36647d92c3f42be39f24d24c48a2 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 4 Jun 2015 07:59:28 +0100
Subject: [PATCH 57/68] Corrected support for disabled rpi when using
@@ -34520,7 +30714,7 @@ Subject: [PATCH 57/68] Corrected support for disabled rpi when using
2 files changed, 11 insertions(+), 9 deletions(-)
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 8d72344..83b0e58 100644
+index b540ca5..c48d0cd 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -795,7 +795,17 @@ typedef struct HEVCPacket {
@@ -34587,23 +30781,23 @@ index 344e021..325b60e 100644
2.5.0
-From 665b1e12a132f7ea798472d46200ad930abe2a82 Mon Sep 17 00:00:00 2001
+From b1ca5230c3a2e5e74945c6f06f75c5dcec62d9d0 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 4 Jun 2015 11:52:55 +0100
Subject: [PATCH 58/68] Draft support for tiles
---
libavcodec/hevc.c | 140 +++++++++++++++++++++++------------------
- libavcodec/hevc.h | 22 +++++--
+ libavcodec/hevc.h | 21 +++++--
libavcodec/hevc_filter.c | 2 +-
libavcodec/hevcpred_template.c | 2 +-
- 4 files changed, 100 insertions(+), 66 deletions(-)
+ 4 files changed, 99 insertions(+), 66 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index a2ba177..f3f5fdb 100644
+index 3fcbc57..23c4e17 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -61,10 +61,10 @@
+@@ -63,10 +63,10 @@
static void rpi_execute_dblk_cmds(HEVCContext *s);
static void rpi_execute_transform(HEVCContext *s);
@@ -34616,7 +30810,7 @@ index a2ba177..f3f5fdb 100644
// Define INTER_PASS0 to do inter prediction in first pass
//#define INTER_PASS0
-@@ -88,16 +88,18 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
+@@ -90,16 +90,18 @@ const uint8_t ff_hevc_pel_weight[65] = { [2] = 0, [4] = 1, [6] = 2, [8] = 3, [12
#ifdef RPI_INTER_QPU
@@ -34640,7 +30834,7 @@ index a2ba177..f3f5fdb 100644
#define ENCODE_COEFFS(c0, c1, c2, c3) (((c0) & 0xff) | ((c1) & 0xff) << 8 | ((c2) & 0xff) << 16 | ((c3) & 0xff) << 24)
-@@ -214,7 +216,7 @@ static void *worker_start(void *arg)
+@@ -216,7 +218,7 @@ static void *worker_start(void *arg)
LOG_ENTER
// printf("%d %d %d : %d %d %d %d\n",s->poc, x_ctb, y_ctb, s->num_pred_cmds,s->num_mv_cmds,s->num_coeffs[2] >> 8,s->num_coeffs[3] >> 10);
#ifndef LAUNCH_PASS0
@@ -34649,7 +30843,7 @@ index a2ba177..f3f5fdb 100644
#endif
#ifndef INTER_PASS0
// Perform inter prediction
-@@ -320,9 +322,14 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -322,9 +324,14 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
#ifdef RPI
av_assert0(sps);
@@ -34666,7 +30860,7 @@ index a2ba177..f3f5fdb 100644
for(job=0;jobx >> 2);
int y1 = y0 + (mv->y >> 2);
@@ -34678,7 +30872,7 @@ index a2ba177..f3f5fdb 100644
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=16) {
int bw = nPbW-start_x;
-@@ -2196,7 +2202,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2198,7 +2204,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter;
}
}
@@ -34687,7 +30881,7 @@ index a2ba177..f3f5fdb 100644
} else
#endif
{
-@@ -2220,12 +2226,10 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2222,12 +2228,10 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int x1_c = x0_c + (mv->x >> (2 + hshift));
int y1_c = y0_c + (mv->y >> (2 + hshift));
@@ -34701,7 +30895,7 @@ index a2ba177..f3f5fdb 100644
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
int bw = nPbW_c-start_x;
-@@ -2249,7 +2253,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2251,7 +2255,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
}
@@ -34710,7 +30904,7 @@ index a2ba177..f3f5fdb 100644
return;
}
#endif
-@@ -2276,10 +2280,9 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2278,10 +2282,9 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int my2_mx2_my_mx = (my_mx << 16) + my_mx;
int x1 = x0 + (mv->x >> 2);
int y1 = y0 + (mv->y >> 2);
@@ -34722,7 +30916,7 @@ index a2ba177..f3f5fdb 100644
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=16) {
int bw = nPbW-start_x;
-@@ -2299,7 +2302,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2301,7 +2304,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter;
}
}
@@ -34731,7 +30925,7 @@ index a2ba177..f3f5fdb 100644
} else
#endif
-@@ -2324,12 +2327,10 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2326,12 +2329,10 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int x1_c = x0_c + (mv->x >> (2 + hshift));
int y1_c = y0_c + (mv->y >> (2 + hshift));
@@ -34745,7 +30939,7 @@ index a2ba177..f3f5fdb 100644
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
int bw = nPbW_c-start_x;
-@@ -2354,7 +2355,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2356,7 +2357,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
}
@@ -34754,7 +30948,7 @@ index a2ba177..f3f5fdb 100644
return;
}
#endif
-@@ -2387,8 +2388,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2389,8 +2390,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int y1 = y0 + (mv->y >> 2);
int x2 = x0 + (mv2->x >> 2);
int y2 = y0 + (mv2->y >> 2);
@@ -34764,7 +30958,7 @@ index a2ba177..f3f5fdb 100644
for(int start_y=0;start_y < nPbH;start_y+=16) { // Potentially we could change the assembly code to support taller sizes in one go
for(int start_x=0;start_x < nPbW;start_x+=8) { // B blocks work 8 at a time
int bw = nPbW-start_x;
-@@ -2404,7 +2404,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2406,7 +2406,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter_b;
}
}
@@ -34773,7 +30967,7 @@ index a2ba177..f3f5fdb 100644
} else
#endif
{
-@@ -2435,9 +2435,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2437,9 +2437,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
int x2_c = x0_c + (mv2->x >> (2 + hshift));
int y2_c = y0_c + (mv2->y >> (2 + hshift));
@@ -34784,7 +30978,7 @@ index a2ba177..f3f5fdb 100644
for(int start_y=0;start_y < nPbH_c;start_y+=16) {
for(int start_x=0;start_x < nPbW_c;start_x+=RPI_CHROMA_BLOCK_WIDTH) {
int bw = nPbW_c-start_x;
-@@ -2466,7 +2465,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+@@ -2468,7 +2467,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
*u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
}
}
@@ -34793,7 +30987,7 @@ index a2ba177..f3f5fdb 100644
return;
}
#endif
-@@ -3101,12 +3100,8 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
+@@ -3103,12 +3102,8 @@ static void rpi_execute_inter_cmds(HEVCContext *s)
static void rpi_do_all_passes(HEVCContext *s)
{
@@ -34808,7 +31002,7 @@ index a2ba177..f3f5fdb 100644
// Perform luma inter prediction
rpi_execute_inter_cmds(s);
// Wait for transform completion
-@@ -3115,18 +3110,18 @@ static void rpi_do_all_passes(HEVCContext *s)
+@@ -3117,18 +3112,18 @@ static void rpi_do_all_passes(HEVCContext *s)
rpi_execute_pred_cmds(s);
// Perform deblocking for CTBs in this row
rpi_execute_dblk_cmds(s);
@@ -34832,7 +31026,7 @@ index a2ba177..f3f5fdb 100644
int pic_width = s->ps.sps->width >> s->ps.sps->hshift[1];
int pic_height = s->ps.sps->height >> s->ps.sps->vshift[1];
int weight_flag = (s->sh.slice_type == P_SLICE && s->ps.pps->weighted_pred_flag) ||
-@@ -3152,6 +3147,8 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -3154,6 +3149,8 @@ static void rpi_inter_clear(HEVCContext *s)
}
*s->u_mvs[job][i]++ = i; // Select section of VPM (avoid collisions with 3d unit)
}
@@ -34841,7 +31035,7 @@ index a2ba177..f3f5fdb 100644
#ifdef RPI_LUMA_QPU
for(i=0;i<12;i++) {
-@@ -3174,8 +3171,11 @@ static void rpi_inter_clear(HEVCContext *s)
+@@ -3176,8 +3173,11 @@ static void rpi_inter_clear(HEVCContext *s)
}
*s->y_mvs[job][i]++ = 0; // Next kernel
}
@@ -34853,7 +31047,7 @@ index a2ba177..f3f5fdb 100644
#ifdef RPI_SIMULATE_QPUS
-@@ -3446,8 +3446,9 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
+@@ -3448,8 +3448,9 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
#endif
@@ -34864,7 +31058,7 @@ index a2ba177..f3f5fdb 100644
{
int k;
#ifdef LAUNCH_PASS0
-@@ -3545,6 +3546,15 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
+@@ -3547,6 +3548,15 @@ static void rpi_execute_inter_qpu(HEVCContext *s)
}
@@ -34880,7 +31074,7 @@ index a2ba177..f3f5fdb 100644
#endif
#ifdef RPI
-@@ -3604,29 +3614,20 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3606,29 +3616,20 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#ifdef RPI
#ifdef RPI_INTER_QPU
s->enable_rpi = s->ps.sps->bit_depth == 8
@@ -34911,7 +31105,7 @@ index a2ba177..f3f5fdb 100644
//printf("L0=%d L1=%d\n",s->sh.nb_refs[L1],s->sh.nb_refs[L1]);
if (!ctb_addr_ts && s->sh.dependent_slice_segment_flag) {
-@@ -3647,8 +3648,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3649,8 +3650,8 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
s->pass1_job = 0;
s->pass2_job = 0;
#endif
@@ -34922,7 +31116,7 @@ index a2ba177..f3f5fdb 100644
#endif
while (more_data && ctb_addr_ts < s->ps.sps->ctb_size) {
-@@ -3666,13 +3667,34 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3668,13 +3669,34 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
s->deblock[ctb_addr_rs].tc_offset = s->sh.tc_offset;
s->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag;
@@ -34958,7 +31152,7 @@ index a2ba177..f3f5fdb 100644
#ifdef RPI_WORKER
if (s->used_for_ref) {
// Split work load onto separate threads so we make as rapid progress as possible with this frame
-@@ -3680,7 +3702,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3682,7 +3704,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
rpi_execute_inter_cmds(s);
#endif
#ifdef LAUNCH_PASS0
@@ -34967,7 +31161,7 @@ index a2ba177..f3f5fdb 100644
#endif
// Pass on this job to worker thread
worker_submit_job(s);
-@@ -3688,9 +3710,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3690,9 +3712,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
worker_pass0_ready(s);
// Prepare the next batch of commands
@@ -34978,7 +31172,7 @@ index a2ba177..f3f5fdb 100644
} else {
// Non-ref frame so do it all on this thread
rpi_do_all_passes(s);
-@@ -3731,7 +3751,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3733,7 +3753,7 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#endif
// Finish off any half-completed rows
@@ -34988,7 +31182,7 @@ index a2ba177..f3f5fdb 100644
}
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 83b0e58..c62540d 100644
+index c48d0cd..3aea745 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -849,8 +849,15 @@ typedef struct HEVCLocalContext {
@@ -35045,11 +31239,10 @@ index 83b0e58..c62540d 100644
// Function pointers
uint32_t mc_filter;
uint32_t mc_filter_b;
-@@ -1099,6 +1109,10 @@ typedef struct HEVCContext {
- int sei_hflip, sei_vflip;
+@@ -1110,6 +1120,9 @@ typedef struct HEVCContext {
+ uint32_t max_mastering_luminance;
+ uint32_t min_mastering_luminance;
- int picture_struct;
-+
+#ifdef RPI
+ int dblk_cmds[RPI_MAX_JOBS][RPI_MAX_DEBLOCK_CMDS][2];
+#endif
@@ -35086,7 +31279,7 @@ index 325b60e..28d2653 100644
2.5.0
-From e8bf19f86fefd76f1f48d7b96bb47ec23c2802fc Mon Sep 17 00:00:00 2001
+From eaaaee12acbb4d4c27191ceafadaa778d3ba0f2f Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 4 Jun 2015 15:48:10 +0100
Subject: [PATCH 59/68] Move deblocker into second pass
@@ -35096,10 +31289,10 @@ Subject: [PATCH 59/68] Move deblocker into second pass
1 file changed, 65 insertions(+), 14 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index f3f5fdb..bd59f02 100644
+index 23c4e17..dde932f 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -65,6 +65,8 @@
+@@ -67,6 +67,8 @@
static void rpi_execute_pred_cmds(HEVCContext *s);
static void rpi_execute_inter_cmds(HEVCContext *s);
static void rpi_begin(HEVCContext *s);
@@ -35108,7 +31301,7 @@ index f3f5fdb..bd59f02 100644
// Define INTER_PASS0 to do inter prediction in first pass
//#define INTER_PASS0
-@@ -225,6 +227,11 @@ static void *worker_start(void *arg)
+@@ -227,6 +229,11 @@ static void *worker_start(void *arg)
// Wait for transform completion
vpu_wait(s->vpu_id);
@@ -35120,7 +31313,7 @@ index f3f5fdb..bd59f02 100644
worker_complete_middle_job(s);
LOG_EXIT
}
-@@ -246,10 +253,6 @@ static void *worker_deblock_start(void *arg)
+@@ -248,10 +255,6 @@ static void *worker_deblock_start(void *arg)
break;
}
LOG_ENTER
@@ -35131,7 +31324,7 @@ index f3f5fdb..bd59f02 100644
worker_complete_job(s);
LOG_EXIT
-@@ -2970,7 +2973,7 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
+@@ -2972,7 +2975,7 @@ static void hls_decode_neighbour(HEVCContext *s, int x_ctb, int y_ctb,
static void rpi_execute_dblk_cmds(HEVCContext *s)
{
int n;
@@ -35140,7 +31333,7 @@ index f3f5fdb..bd59f02 100644
int ctb_size = 1 << s->ps.sps->log2_ctb_size;
int (*p)[2] = s->dblk_cmds[job];
for(n = s->num_dblk_cmds[job]; n>0 ;n--,p++) {
-@@ -3008,7 +3011,7 @@ static void rpi_execute_transform(HEVCContext *s)
+@@ -3010,7 +3013,7 @@ static void rpi_execute_transform(HEVCContext *s)
static void rpi_execute_pred_cmds(HEVCContext *s)
{
int i;
@@ -35149,7 +31342,7 @@ index f3f5fdb..bd59f02 100644
HEVCPredCmd *cmd = s->univ_pred_cmds[job];
#ifdef RPI_WORKER
HEVCLocalContextIntra *lc = &s->HEVClcIntra;
-@@ -3493,11 +3496,10 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
+@@ -3495,11 +3498,10 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
#ifdef RPI_MULTI_MAILBOX
#ifdef RPI_CACHE_UNIF_MVS
@@ -35163,7 +31356,7 @@ index f3f5fdb..bd59f02 100644
s->vpu_id = vpu_qpu_post_code( vpu_get_fn(), vpu_get_constants(), s->coeffs_buf_vc[job][2], s->num_coeffs[job][2] >> 8, s->coeffs_buf_vc[job][3], s->num_coeffs[job][3] >> 10, 0,
qpu_get_fn(QPU_MC_SETUP_UV),
(uint32_t)(unif_vc+(s->mvs_base[job][0 ] - (uint32_t*)s->unif_mvs_ptr[job].arm)),
-@@ -3600,6 +3602,60 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
+@@ -3602,6 +3604,60 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
#endif
}
@@ -35224,7 +31417,7 @@ index f3f5fdb..bd59f02 100644
#endif
static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
-@@ -4050,11 +4106,6 @@ static int hevc_frame_start(HEVCContext *s)
+@@ -4116,11 +4172,6 @@ static int hevc_frame_start(HEVCContext *s)
if (!s->avctx->hwaccel)
ff_thread_finish_setup(s->avctx);
@@ -35240,7 +31433,7 @@ index f3f5fdb..bd59f02 100644
2.5.0
-From bd42b24c8f7e1f0d2bcfa476d2e1aea20aa3723e Mon Sep 17 00:00:00 2001
+From f45417c35888b74a36a5ecc6959480787e727b0c Mon Sep 17 00:00:00 2001
From: popcornmix
Date: Thu, 4 Jun 2015 16:10:23 +0100
Subject: [PATCH 60/68] Change order of ctu accesses to improve qpu performance
@@ -35250,10 +31443,10 @@ Subject: [PATCH 60/68] Change order of ctu accesses to improve qpu performance
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index bd59f02..ff93f6c 100644
+index dde932f..e247444 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -3724,19 +3724,19 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3726,19 +3726,19 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
s->filter_slice_edges[ctb_addr_rs] = s->sh.slice_loop_filter_across_slices_enabled_flag;
#ifdef RPI_INTER_QPU
@@ -35281,7 +31474,7 @@ index bd59f02..ff93f6c 100644
2.5.0
-From 3ba78b5fe86fccfb132068603ad1db87ce44ab6c Mon Sep 17 00:00:00 2001
+From 8d8b31eeffebf0a40c3b267d1b16401ef267bbf5 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Mon, 8 Jun 2015 09:36:59 +0100
Subject: [PATCH 61/68] Removed deblocker thread
@@ -35292,10 +31485,10 @@ Subject: [PATCH 61/68] Removed deblocker thread
2 files changed, 4 insertions(+), 77 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index ff93f6c..43f7ce5 100644
+index e247444..bbb7ad3 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -68,11 +68,6 @@
+@@ -70,11 +70,6 @@
static void flush_frame(HEVCContext *s,AVFrame *frame);
static void flush_frame3(HEVCContext *s,AVFrame *frame,GPU_MEM_PTR_T *p0,GPU_MEM_PTR_T *p1,GPU_MEM_PTR_T *p2);
@@ -35307,7 +31500,7 @@ index ff93f6c..43f7ce5 100644
#endif
// #define DISABLE_MC
-@@ -145,24 +140,12 @@ static void worker_submit_job(HEVCContext *s)
+@@ -147,24 +142,12 @@ static void worker_submit_job(HEVCContext *s)
}
// Call this to say we have completed pass1
@@ -35333,7 +31526,7 @@ index ff93f6c..43f7ce5 100644
pthread_cond_broadcast(&s->worker_cond_head); // Let people know that the head has moved
pthread_mutex_unlock(&s->worker_mutex);
LOG_EXIT
-@@ -206,7 +189,7 @@ static void *worker_start(void *arg)
+@@ -208,7 +191,7 @@ static void *worker_start(void *arg)
while(1) {
pthread_mutex_lock(&s->worker_mutex);
@@ -35342,7 +31535,7 @@ index ff93f6c..43f7ce5 100644
{
pthread_cond_wait(&s->worker_cond_tail, &s->worker_mutex);
}
-@@ -217,13 +200,9 @@ static void *worker_start(void *arg)
+@@ -219,13 +202,9 @@ static void *worker_start(void *arg)
}
LOG_ENTER
// printf("%d %d %d : %d %d %d %d\n",s->poc, x_ctb, y_ctb, s->num_pred_cmds,s->num_mv_cmds,s->num_coeffs[2] >> 8,s->num_coeffs[3] >> 10);
@@ -35356,7 +31549,7 @@ index ff93f6c..43f7ce5 100644
// Wait for transform completion
vpu_wait(s->vpu_id);
-@@ -232,28 +211,6 @@ static void *worker_start(void *arg)
+@@ -234,28 +213,6 @@ static void *worker_start(void *arg)
// Perform deblocking for CTBs in this row
rpi_execute_dblk_cmds(s);
@@ -35385,7 +31578,7 @@ index ff93f6c..43f7ce5 100644
worker_complete_job(s);
LOG_EXIT
}
-@@ -2985,11 +2942,7 @@ static void rpi_execute_dblk_cmds(HEVCContext *s)
+@@ -2987,11 +2944,7 @@ static void rpi_execute_dblk_cmds(HEVCContext *s)
static void rpi_execute_transform(HEVCContext *s)
{
int i=2;
@@ -35397,7 +31590,7 @@ index ff93f6c..43f7ce5 100644
//int j;
//int16_t *coeffs = s->coeffs_buf_arm[i];
//for(j=s->num_coeffs[i]; j > 0; j-= 16*16, coeffs+=16*16) {
-@@ -3044,11 +2997,7 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
+@@ -3046,11 +2999,7 @@ static void rpi_execute_pred_cmds(HEVCContext *s)
static void rpi_execute_inter_cmds(HEVCContext *s)
{
@@ -35409,7 +31602,7 @@ index ff93f6c..43f7ce5 100644
HEVCMvCmd *cmd = s->unif_mv_cmds[job];
int n,cidx;
AVFrame myref;
-@@ -3454,11 +3403,7 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
+@@ -3456,11 +3405,7 @@ static void rpi_simulate_inter_qpu(HEVCContext *s)
static void rpi_launch_vpu_qpu(HEVCContext *s)
{
int k;
@@ -35421,7 +31614,7 @@ index ff93f6c..43f7ce5 100644
int i;
uint32_t *unif_vc = (uint32_t *)s->unif_mvs_ptr[job].vc;
#ifdef RPI_LUMA_QPU
-@@ -3561,10 +3506,12 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
+@@ -3563,10 +3508,12 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
#ifdef RPI
@@ -35434,7 +31627,7 @@ index ff93f6c..43f7ce5 100644
static void flush_frame(HEVCContext *s,AVFrame *frame)
{
-@@ -3702,7 +3649,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3704,7 +3651,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#ifdef RPI_WORKER
s->pass0_job = 0;
s->pass1_job = 0;
@@ -35442,7 +31635,7 @@ index ff93f6c..43f7ce5 100644
#endif
#ifdef RPI
rpi_begin(s);
-@@ -3754,12 +3700,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3756,12 +3702,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
#ifdef RPI_WORKER
if (s->used_for_ref) {
// Split work load onto separate threads so we make as rapid progress as possible with this frame
@@ -35455,7 +31648,7 @@ index ff93f6c..43f7ce5 100644
// Pass on this job to worker thread
worker_submit_job(s);
// Make sure we have space to prepare the next job
-@@ -3801,8 +3741,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
+@@ -3803,8 +3743,6 @@ static int hls_decode_entry(AVCodecContext *avctxt, void *isFilterThread)
// Wait for the worker to finish all its jobs
if (s->enable_rpi) {
worker_wait(s);
@@ -35464,7 +31657,7 @@ index ff93f6c..43f7ce5 100644
}
#endif
-@@ -4488,16 +4426,13 @@ static av_cold void hevc_init_worker(HEVCContext *s)
+@@ -4554,16 +4492,13 @@ static av_cold void hevc_init_worker(HEVCContext *s)
{
int err;
pthread_cond_init(&s->worker_cond_head, NULL);
@@ -35481,7 +31674,7 @@ index ff93f6c..43f7ce5 100644
if (err) {
printf("Failed to create worker thread\n");
exit(-1);
-@@ -4509,17 +4444,13 @@ static av_cold void hevc_exit_worker(HEVCContext *s)
+@@ -4575,17 +4510,13 @@ static av_cold void hevc_exit_worker(HEVCContext *s)
void *res;
s->kill_worker=1;
pthread_cond_broadcast(&s->worker_cond_tail);
@@ -35500,7 +31693,7 @@ index ff93f6c..43f7ce5 100644
s->kill_worker=0;
}
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index c62540d..6c0d0b6 100644
+index 3aea745..a577fcb 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -957,7 +957,6 @@ typedef struct HEVCContext {
@@ -35531,7 +31724,7 @@ index c62540d..6c0d0b6 100644
2.5.0
-From d0720e2a6f21bbdf2ad1d52227ae272db4cf9dc0 Mon Sep 17 00:00:00 2001
+From 9ad14cb77eeec547db386bd2c3a6e25f41ae5b31 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Mon, 8 Jun 2015 11:04:43 +0100
Subject: [PATCH 62/68] Reduced amount of output frame that is invalidated
@@ -35541,10 +31734,10 @@ Subject: [PATCH 62/68] Reduced amount of output frame that is invalidated
1 file changed, 29 insertions(+), 16 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 43f7ce5..ef61788 100644
+index bbb7ad3..2374c2b 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -66,7 +66,7 @@
+@@ -68,7 +68,7 @@
static void rpi_execute_inter_cmds(HEVCContext *s);
static void rpi_begin(HEVCContext *s);
static void flush_frame(HEVCContext *s,AVFrame *frame);
@@ -35553,7 +31746,7 @@ index 43f7ce5..ef61788 100644
#endif
-@@ -3441,9 +3441,9 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
+@@ -3443,9 +3443,9 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
#ifdef RPI_MULTI_MAILBOX
#ifdef RPI_CACHE_UNIF_MVS
@@ -35565,7 +31758,7 @@ index 43f7ce5..ef61788 100644
#endif
s->vpu_id = vpu_qpu_post_code( vpu_get_fn(), vpu_get_constants(), s->coeffs_buf_vc[job][2], s->num_coeffs[job][2] >> 8, s->coeffs_buf_vc[job][3], s->num_coeffs[job][3] >> 10, 0,
qpu_get_fn(QPU_MC_SETUP_UV),
-@@ -3517,6 +3517,7 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
+@@ -3519,6 +3519,7 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
{
#ifdef RPI_FAST_CACHEFLUSH
struct vcsm_user_clean_invalid_s iocache = {};
@@ -35573,7 +31766,7 @@ index 43f7ce5..ef61788 100644
int n = s->ps.sps->height;
int curr_y = 0;
int curr_uv = 0;
-@@ -3524,22 +3525,21 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
+@@ -3526,22 +3527,21 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
int sz,base;
sz = s->frame->linesize[1] * (n_uv-curr_uv);
base = s->frame->linesize[1] * curr_uv;
@@ -35599,7 +31792,7 @@ index 43f7ce5..ef61788 100644
iocache.s[2].size = sz;
vcsm_clean_invalid( &iocache );
#else
-@@ -3549,33 +3549,46 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
+@@ -3551,33 +3551,46 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
#endif
}
@@ -35659,7 +31852,7 @@ index 43f7ce5..ef61788 100644
2.5.0
-From 980ce082dd1c0101e2aec64121c9de1d03a287f4 Mon Sep 17 00:00:00 2001
+From e5e5d6e39c9361a4c842656103b7411b75098c0c Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Mon, 8 Jun 2015 11:55:29 +0100
Subject: [PATCH 63/68] Packed 16x16 and 32x32 into the same buffer
@@ -35671,10 +31864,10 @@ Subject: [PATCH 63/68] Packed 16x16 and 32x32 into the same buffer
3 files changed, 24 insertions(+), 11 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index ef61788..8c6db35 100644
+index 2374c2b..3df6308 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -297,12 +297,12 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -299,12 +299,12 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
s->coeffs_buf_arm[job][0] = (int16_t*) s->coeffs_buf_default[job].arm;
if (!s->coeffs_buf_arm[job][0])
goto fail;
@@ -35689,7 +31882,7 @@ index ef61788..8c6db35 100644
s->coeffs_buf_vc[job][3] = sizeof(int16_t) * coefs_per_row + s->coeffs_buf_vc[job][2];
}
}
-@@ -2943,15 +2943,20 @@ static void rpi_execute_transform(HEVCContext *s)
+@@ -2945,15 +2945,20 @@ static void rpi_execute_transform(HEVCContext *s)
{
int i=2;
int job = s->pass1_job;
@@ -35716,7 +31909,7 @@ index ef61788..8c6db35 100644
s->num_coeffs[job][3] >> 10, 0, &s->coeffs_buf_accelerated[job]);
//vpu_execute_code( vpu_get_fn(), vpu_get_constants(), s->coeffs_buf_vc[2], s->num_coeffs[2] >> 8, s->coeffs_buf_vc[3], s->num_coeffs[3] >> 10, 0);
//gpu_cache_flush(&s->coeffs_buf_accelerated);
-@@ -3445,7 +3450,8 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
+@@ -3447,7 +3452,8 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
#else
flush_frame3(s, s->frame,&s->coeffs_buf_accelerated[job],NULL,NULL, job);
#endif
@@ -35763,7 +31956,7 @@ index 4480f72..0121fca 100644
2.5.0
-From dd561eb52a075c09da89bf20f8d18fb92123ec2c Mon Sep 17 00:00:00 2001
+From a1c0980a8ce8b0059637e9fdc61b1cbd64c58e43 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Thu, 25 Jun 2015 09:02:47 +0100
Subject: [PATCH 64/68] Moved luma deblock to VPU
@@ -35779,10 +31972,10 @@ Subject: [PATCH 64/68] Moved luma deblock to VPU
7 files changed, 2378 insertions(+), 13 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index 8c6db35..da4bebb 100644
+index 3df6308..0ecaf05 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -244,6 +244,12 @@ static void pic_arrays_free(HEVCContext *s)
+@@ -246,6 +246,12 @@ static void pic_arrays_free(HEVCContext *s)
}
}
#endif
@@ -35795,7 +31988,7 @@ index 8c6db35..da4bebb 100644
av_freep(&s->sao);
av_freep(&s->deblock);
-@@ -281,12 +287,12 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -283,12 +289,12 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
int min_pu_size = sps->min_pu_width * sps->min_pu_height;
#ifdef RPI
@@ -35809,7 +32002,7 @@ index 8c6db35..da4bebb 100644
s->max_ctu_count = coefs_per_luma / coefs_in_ctb;
s->ctu_per_y_chan = s->max_ctu_count / 12;
s->ctu_per_uv_chan = s->max_ctu_count / 8;
-@@ -307,6 +313,16 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -309,6 +315,16 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
}
}
#endif
@@ -35827,7 +32020,7 @@ index 8c6db35..da4bebb 100644
s->bs_width = (width >> 2) + 1;
s->bs_height = (height >> 2) + 1;
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 6c0d0b6..c933757 100644
+index a577fcb..b1d3ee0 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -56,6 +56,8 @@
@@ -38370,7 +34563,7 @@ index e86eb30..c5d8b29 100644
2.5.0
-From 8864ce029b80325be328e0b2493f5ba18b10c906 Mon Sep 17 00:00:00 2001
+From 1c7aae12a916196defd7ca1d5e8f052551535034 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 1 Jul 2015 09:21:17 +0100
Subject: [PATCH 65/68] Added ability to combine jobs
@@ -38523,7 +34716,7 @@ index 05b2169..91777be 100644
2.5.0
-From 8289de8799cb666404d8d1a01c211a7be17bae61 Mon Sep 17 00:00:00 2001
+From 3b056ce7d9bc16ac6d62fc84cb26e0991741ec26 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 1 Jul 2015 12:53:10 +0100
Subject: [PATCH 66/68] Added chroma deblocking
@@ -38539,10 +34732,10 @@ Subject: [PATCH 66/68] Added chroma deblocking
7 files changed, 988 insertions(+), 25 deletions(-)
diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
-index da4bebb..d56f777 100644
+index 0ecaf05..35a1394 100644
--- a/libavcodec/hevc.c
+++ b/libavcodec/hevc.c
-@@ -249,6 +249,14 @@ static void pic_arrays_free(HEVCContext *s)
+@@ -251,6 +251,14 @@ static void pic_arrays_free(HEVCContext *s)
gpu_free(&s->y_setup_ptr);
s->y_setup_arm = 0;
}
@@ -38557,7 +34750,7 @@ index da4bebb..d56f777 100644
#endif
av_freep(&s->sao);
av_freep(&s->deblock);
-@@ -322,6 +330,18 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
+@@ -324,6 +332,18 @@ static int pic_arrays_init(HEVCContext *s, const HEVCSPS *sps)
s->y_setup_vc = (void*)s->y_setup_ptr.vc;
memset(s->y_setup_arm, 0, s->y_setup_ptr.numbytes);
printf("Setup %d by %d by %d\n",s->setup_width,s->setup_height,sizeof(*s->y_setup_arm));
@@ -38577,7 +34770,7 @@ index da4bebb..d56f777 100644
s->bs_width = (width >> 2) + 1;
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index c933757..6675a4f 100644
+index b1d3ee0..aa7cdc3 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -55,7 +55,7 @@
@@ -39751,7 +35944,7 @@ index 0686249..64bf5b0 100644
2.5.0
-From f7a8b294a317dc015d19a342aa20a994a299676d Mon Sep 17 00:00:00 2001
+From 9f07110097a85bc056c338f9bd1891ca2027f580 Mon Sep 17 00:00:00 2001
From: Ben Avison
Date: Tue, 23 Jun 2015 23:42:03 +0100
Subject: [PATCH 67/68] armv7/hevc: Optimise deblocking boundary strength
@@ -39915,7 +36108,7 @@ index e5da7e9..49c70dd 100644
+ c->hevc_deblocking_boundary_strengths = ff_hevc_deblocking_boundary_strengths_neon;
}
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 6675a4f..10fbccc 100644
+index aa7cdc3..cfa7c61 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -683,17 +683,6 @@ typedef struct CodingUnit {
@@ -40381,7 +36574,7 @@ index 9f1f6dd..e221e54 100644
2.5.0
-From 95c6d1107c1dc60fd40abeb9eadb69b3937ce9f5 Mon Sep 17 00:00:00 2001
+From 50c89ce45ad633db0a48f084d5ecae0ae989e704 Mon Sep 17 00:00:00 2001
From: Peter de Rivaz
Date: Wed, 15 Jul 2015 09:09:11 +0100
Subject: [PATCH 68/68] Only enable qpu when needed
@@ -40392,7 +36585,7 @@ Subject: [PATCH 68/68] Only enable qpu when needed
2 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/libavcodec/hevc.h b/libavcodec/hevc.h
-index 10fbccc..a8ff7b8 100644
+index cfa7c61..cb4350d 100644
--- a/libavcodec/hevc.h
+++ b/libavcodec/hevc.h
@@ -56,7 +56,7 @@
@@ -40476,2291 +36669,1469 @@ index 5aa0432..ffd13ca 100644
--
2.5.0
-From 9421229d7f8e6ef6cfb8a1b30f731f91c6586aca Mon Sep 17 00:00:00 2001
+From 544f5eb0b6f8cc1ad316a94cae5e78eadf2e1ec9 Mon Sep 17 00:00:00 2001
From: John Cox
-Date: Wed, 13 Jan 2016 16:13:33 +0000
-Subject: [PATCH] H.265 residual decode rework (v2)
+Date: Tue, 9 Feb 2016 11:57:40 +0000
+Subject: [PATCH 1/2] Zero copy code v6
-Rework the cabac decode functions
-Simplify the code flow and variable usage where possible
-
-(Remove profiling and other spurious deltas that were in v1)
+This version has GPU buffer pooling code
---
- libavcodec/arm/cabac.h | 155 ++++-
- libavcodec/arm/hevc_cabac.h | 491 +++++++++++++++
- libavcodec/arm/hevcdsp_deblock_neon.S | 13 +-
- libavcodec/arm/hevcdsp_epel_neon.S | 9 +-
- libavcodec/cabac.c | 11 +-
- libavcodec/cabac.h | 9 +-
- libavcodec/cabac_functions.h | 15 +-
- libavcodec/hevc_cabac.c | 1098 +++++++++++++++++++++++++--------
- 8 files changed, 1534 insertions(+), 267 deletions(-)
- create mode 100644 libavcodec/arm/hevc_cabac.h
+ ffmpeg.c | 123 +++++++++-----
+ libavcodec/Makefile | 2 +
+ libavcodec/avcodec.h | 6 +
+ libavcodec/hevc.c | 92 ++++++-----
+ libavcodec/hevc_filter.c | 83 +++++-----
+ libavcodec/rpi_qpu.c | 2 +-
+ libavcodec/rpi_qpu.h | 109 ++++++++++++-
+ libavcodec/rpi_zc.c | 406 +++++++++++++++++++++++++++++++++++++++++++++++
+ libavcodec/rpi_zc.h | 83 ++++++++++
+ 9 files changed, 779 insertions(+), 127 deletions(-)
+ create mode 100644 libavcodec/rpi_zc.c
+ create mode 100644 libavcodec/rpi_zc.h
-diff --git a/libavcodec/arm/cabac.h b/libavcodec/arm/cabac.h
-index fdbf86b..0a3980a 100644
---- a/libavcodec/arm/cabac.h
-+++ b/libavcodec/arm/cabac.h
-@@ -26,13 +26,34 @@
- #include "libavutil/internal.h"
- #include "libavcodec/cabac.h"
+diff --git a/ffmpeg.c b/ffmpeg.c
+index 8828f48..36dc1a3 100644
+--- a/ffmpeg.c
++++ b/ffmpeg.c
+@@ -25,7 +25,7 @@
-+
-+#if UNCHECKED_BITSTREAM_READER
-+#define LOAD_16BITS_BEHI\
-+ "ldrh %[tmp] , [%[ptr]] , #2 \n\t"\
-+ "rev %[tmp] , %[tmp] \n\t"
-+#elif CONFIG_THUMB
-+#define LOAD_16BITS_BEHI\
-+ "ldr %[tmp] , [%[c], %[end]] \n\t"\
-+ "cmp %[tmp] , %[ptr] \n\t"\
-+ "it cs \n\t"\
-+ "ldrhcs %[tmp] , [%[ptr]] , #2 \n\t"\
-+ "rev %[tmp] , %[tmp] \n\t"
-+#else
-+#define LOAD_16BITS_BEHI\
-+ "ldr %[tmp] , [%[c], %[end]] \n\t"\
-+ "cmp %[tmp] , %[ptr] \n\t"\
-+ "ldrcsh %[tmp] , [%[ptr]] , #2 \n\t"\
-+ "rev %[tmp] , %[tmp] \n\t"
-+#endif
-+
-+
- #define get_cabac_inline get_cabac_inline_arm
- static av_always_inline int get_cabac_inline_arm(CABACContext *c,
- uint8_t *const state)
- {
- int bit;
-+#if 0
- void *reg_b, *reg_c, *tmp;
--
- __asm__ volatile(
- "ldrb %[bit] , [%[state]] \n\t"
- "add %[r_b] , %[tables] , %[lps_off] \n\t"
-@@ -100,9 +121,141 @@ static av_always_inline int get_cabac_inline_arm(CABACContext *c,
- [mlps_off]"I"(H264_MLPS_STATE_OFFSET + 128)
- : "memory", "cc"
- );
-+#else
-+ // *** Not thumb compatible yet
-+ unsigned int reg_b, tmp;
-+ __asm__ (
-+ "ldrb %[bit] , [%[state]] \n\t"
-+ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t"
-+ "and %[tmp] , %[range] , #0xC0 \n\t"
-+ "add %[r_b] , %[r_b] , %[bit] \n\t"
-+ "ldrb %[tmp] , [%[r_b] , %[tmp], lsl #1] \n\t"
-+// %bit = *state
-+// %range = range
-+// %tmp = RangeLPS
-+ "sub %[range] , %[range] , %[tmp] \n\t"
-+
-+ "cmp %[low] , %[range] , lsl #17 \n\t"
-+ "ittt ge \n\t"
-+ "subge %[low] , %[low] , %[range], lsl #17 \n\t"
-+ "mvnge %[bit] , %[bit] \n\t"
-+ "movge %[range] , %[tmp] \n\t"
-+
-+ "clz %[tmp] , %[range] \n\t"
-+ "sub %[tmp] , #23 \n\t"
-+
-+ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t"
-+ "lsl %[low] , %[low] , %[tmp] \n\t"
-+ "lsl %[range] , %[range] , %[tmp] \n\t"
-+
-+ "strb %[r_b] , [%[state]] \n\t"
-+ "lsls %[tmp] , %[low] , #16 \n\t"
-+
-+ "bne 2f \n\t"
-+ LOAD_16BITS_BEHI
-+ "lsr %[tmp] , %[tmp] , #15 \n\t"
-+ "movw %[r_b] , #0xFFFF \n\t"
-+ "sub %[tmp] , %[tmp] , %[r_b] \n\t"
-+
-+ "rbit %[r_b] , %[low] \n\t"
-+ "clz %[r_b] , %[r_b] \n\t"
-+ "sub %[r_b] , %[r_b] , #16 \n\t"
-+#if CONFIG_THUMB
-+ "lsl %[tmp] , %[tmp] , %[r_b] \n\t"
-+ "add %[low] , %[low] , %[tmp] \n\t"
-+#else
-+ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t"
-+#endif
-+ "2: \n\t"
-+ : [bit]"=&r"(bit),
-+ [low]"+&r"(c->low),
-+ [range]"+&r"(c->range),
-+ [r_b]"=&r"(reg_b),
-+ [ptr]"+&r"(c->bytestream),
-+ [tmp]"=&r"(tmp)
-+ : [state]"r"(state),
-+ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128),
-+ [byte]"M"(offsetof(CABACContext, bytestream)),
-+#if !UNCHECKED_BITSTREAM_READER
-+ [c]"r"(c),
-+ [end]"M"(offsetof(CABACContext, bytestream_end)),
-+#endif
-+ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET)
-+ : "memory", "cc"
-+ );
-+#endif
+ #ifdef RPI
+ #define RPI_DISPLAY
+-//#define RPI_ZERO_COPY
++#define RPI_ZERO_COPY
+ #endif
- return bit & 1;
- }
-+
-+#define get_cabac_bypass get_cabac_bypass_arm
-+static inline int get_cabac_bypass_arm(CABACContext * const c)
-+{
-+ int rv = 0;
-+ unsigned int tmp;
-+ __asm (
-+ "lsl %[low] , #1 \n\t"
-+ "cmp %[low] , %[range] , lsl #17 \n\t"
-+ "adc %[rv] , %[rv] , #0 \n\t"
-+ "it cs \n\t"
-+ "subcs %[low] , %[low] , %[range], lsl #17 \n\t"
-+ "lsls %[tmp] , %[low] , #16 \n\t"
-+ "bne 1f \n\t"
-+ LOAD_16BITS_BEHI
-+ "add %[low] , %[low] , %[tmp], lsr #15 \n\t"
-+ "movw %[tmp] , #0xFFFF \n\t"
-+ "sub %[low] , %[low] , %[tmp] \n\t"
-+ "1: \n\t"
-+ : // Outputs
-+ [rv]"+&r"(rv),
-+ [low]"+&r"(c->low),
-+ [tmp]"=&r"(tmp),
-+ [ptr]"+&r"(c->bytestream)
-+ : // Inputs
-+#if !UNCHECKED_BITSTREAM_READER
-+ [c]"r"(c),
-+ [end]"M"(offsetof(CABACContext, bytestream_end)),
-+#endif
-+ [range]"r"(c->range)
-+ : "cc"
-+ );
-+ return rv;
-+}
-+
-+
-+#define get_cabac_bypass_sign get_cabac_bypass_sign_arm
-+static inline int get_cabac_bypass_sign_arm(CABACContext * const c, int rv)
-+{
-+ unsigned int tmp;
-+ __asm (
-+ "lsl %[low] , #1 \n\t"
-+ "cmp %[low] , %[range] , lsl #17 \n\t"
-+ "ite cc \n\t"
-+ "rsbcc %[rv] , %[rv] , #0 \n\t"
-+ "subcs %[low] , %[low] , %[range], lsl #17 \n\t"
-+ "lsls %[tmp] , %[low] , #16 \n\t"
-+ "bne 1f \n\t"
-+ LOAD_16BITS_BEHI
-+ "add %[low] , %[low] , %[tmp], lsr #15 \n\t"
-+ "movw %[tmp] , #0xFFFF \n\t"
-+ "sub %[low] , %[low] , %[tmp] \n\t"
-+ "1: \n\t"
-+ : // Outputs
-+ [rv]"+&r"(rv),
-+ [low]"+&r"(c->low),
-+ [tmp]"=&r"(tmp),
-+ [ptr]"+&r"(c->bytestream)
-+ : // Inputs
-+#if !UNCHECKED_BITSTREAM_READER
-+ [c]"r"(c),
-+ [end]"M"(offsetof(CABACContext, bytestream_end)),
-+#endif
-+ [range]"r"(c->range)
-+ : "cc"
-+ );
-+ return rv;
-+}
-+
- #endif /* HAVE_ARMV6T2_INLINE */
-
- #endif /* AVCODEC_ARM_CABAC_H */
-diff --git a/libavcodec/arm/hevc_cabac.h b/libavcodec/arm/hevc_cabac.h
-new file mode 100644
-index 0000000..31d3c59
---- /dev/null
-+++ b/libavcodec/arm/hevc_cabac.h
-@@ -0,0 +1,491 @@
-+/*
-+ * This file is part of FFmpeg.
-+ *
-+ * FFmpeg is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU Lesser General Public
-+ * License as published by the Free Software Foundation; either
-+ * version 2.1 of the License, or (at your option) any later version.
-+ *
-+ * FFmpeg is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-+ * Lesser General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU Lesser General Public
-+ * License along with FFmpeg; if not, write to the Free Software
-+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-+ */
-+
-+#ifndef AVCODEC_ARM_HEVC_CABAC_H
-+#define AVCODEC_ARM_HEVC_CABAC_H
-+
-+#include "config.h"
-+#if HAVE_ARMV6T2_INLINE
-+
-+#define hevc_mem_bits32 hevc_mem_bits32_arm
-+static inline uint32_t hevc_mem_bits32_arm(const void * p, const unsigned int bits)
-+{
-+ unsigned int n;
-+ __asm__ (
-+ "rev %[n], %[x] \n\t"
-+ : [n]"=r"(n)
-+ : [x]"r"(*(const uint32_t *)((const uint8_t *)p + (bits >> 3)))
-+ :
-+ );
-+ return n << (bits & 7);
-+}
-+
-+
-+// ---------------------------------------------------------------------------
-+//
-+// Helper fns - little bits of code where ARM has an instraction that the
-+// compiler doesn't know about / use
-+
-+#define trans_scale_sat trans_scale_sat_arm
-+static inline int trans_scale_sat_arm(const int level, const unsigned int scale, const unsigned int scale_m, const unsigned int shift)
-+{
-+ int rv;
-+ int t = ((level * (int)(scale * scale_m)) >> shift) + 1;
-+
-+ __asm__ (
-+ "ssat %[rv], #16, %[t], ASR #1 \n\t"
-+ : [rv]"=r"(rv)
-+ : [t]"r"(t)
-+ :
-+ );
-+ return rv;
-+}
-+
-+#define update_rice update_rice_arm
-+static inline void update_rice_arm(uint8_t * const stat_coeff,
-+ const unsigned int last_coeff_abs_level_remaining,
-+ const unsigned int c_rice_param)
-+{
-+ int t;
-+ __asm__ (
-+ "lsl %[t], %[coeff], #1 \n\t"
-+ "lsrs %[t], %[t], %[shift] \n\t"
-+ "it eq \n\t"
-+ "subeq %[stat], %[stat], #1 \n\t"
-+ "cmp %[t], #6 \n\t"
-+ "adc %[stat], %[stat], #0 \n\t"
-+ "usat %[stat], #8, %[stat] \n\t"
-+ : [stat]"+&r"(*stat_coeff),
-+ [t]"=&r"(t)
-+ : [coeff]"r"(last_coeff_abs_level_remaining),
-+ [shift]"r"(c_rice_param)
-+ : "cc"
-+ );
-+}
-+
-+// ---------------------------------------------------------------------------
-+//
-+// CABAC get loops
-+//
-+// Where the loop is simple enough we can normally do 10-30% better than the
-+// compiler
-+
-+// Get the residual greater than 1 bits
-+
-+#define get_cabac_greater1_bits get_cabac_greater1_bits_arm
-+static inline unsigned int get_cabac_greater1_bits_arm(CABACContext * const c, const unsigned int n,
-+ uint8_t * const state0)
-+{
-+ unsigned int i, reg_b, st, tmp, bit, rv;
-+ __asm__ (
-+ "mov %[i] , #0 \n\t"
-+ "mov %[rv] , #0 \n\t"
-+ "1: \n\t"
-+ "add %[i] , %[i] , #1 \n\t"
-+ "cmp %[rv] , #0 \n\t"
-+ "ite eq \n\t"
-+ "usateq %[st] , #2 , %[i] \n\t"
-+ "movne %[st] , #0 \n\t"
-+
-+ "ldrb %[bit] , [%[state0], %[st]] \n\t"
-+ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t"
-+ "and %[tmp] , %[range] , #0xC0 \n\t"
-+ "add %[r_b] , %[r_b] , %[bit] \n\t"
-+ "ldrb %[tmp] , [%[r_b], %[tmp], lsl #1] \n\t"
-+ "sub %[range] , %[range] , %[tmp] \n\t"
-+
-+ "cmp %[low] , %[range], lsl #17 \n\t"
-+ "ittt ge \n\t"
-+ "subge %[low] , %[low] , %[range], lsl #17 \n\t"
-+ "mvnge %[bit] , %[bit] \n\t"
-+ "movge %[range] , %[tmp] \n\t"
-+
-+ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t"
-+ "and %[bit] , %[bit] , #1 \n\t"
-+ "orr %[rv] , %[bit] , %[rv], lsl #1 \n\t"
-+
-+ "clz %[tmp] , %[range] \n\t"
-+ "sub %[tmp] , #23 \n\t"
-+
-+ "lsl %[low] , %[low] , %[tmp] \n\t"
-+ "lsl %[range] , %[range] , %[tmp] \n\t"
-+
-+ "strb %[r_b] , [%[state0], %[st]] \n\t"
-+// There is a small speed gain from combining both conditions, using a single
-+// branch and then working out what that meant later
-+ "lsls %[tmp] , %[low] , #16 \n\t"
-+ "it ne \n\t"
-+ "cmpne %[n] , %[i] \n\t"
-+ "bne 1b \n\t"
-+
-+// If reload is not required then we must have run out of flags to decode
-+ "tst %[tmp] , %[tmp] \n\t"
-+ "bne 2f \n\t"
-+
-+// Do reload
-+ "ldrh %[tmp] , [%[bptr]] , #2 \n\t"
-+ "movw %[r_b] , #0xFFFF \n\t"
-+ "rev %[tmp] , %[tmp] \n\t"
-+ "rsb %[tmp] , %[r_b] , %[tmp], lsr #15 \n\t"
-+
-+ "rbit %[r_b] , %[low] \n\t"
-+ "clz %[r_b] , %[r_b] \n\t"
-+ "sub %[r_b] , %[r_b] , #16 \n\t"
-+
-+#if CONFIG_THUMB
-+ "lsl %[tmp] , %[tmp] , %[r_b] \n\t"
-+ "add %[low] , %[low] , %[tmp] \n\t"
-+#else
-+ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t"
-+#endif
-+
-+ "cmp %[n] , %[i] \n\t"
-+ "bne 1b \n\t"
-+ "2: \n\t"
-+ : [bit]"=&r"(bit),
-+ [low]"+&r"(c->low),
-+ [range]"+&r"(c->range),
-+ [r_b]"=&r"(reg_b),
-+ [bptr]"+&r"(c->bytestream),
-+ [i]"=&r"(i),
-+ [tmp]"=&r"(tmp),
-+ [st]"=&r"(st),
-+ [rv]"=&r"(rv)
-+ : [state0]"r"(state0),
-+ [n]"r"(n),
-+ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128),
-+ [byte]"M"(offsetof(CABACContext, bytestream)),
-+ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET)
-+ : "memory", "cc"
-+ );
-+ return rv;
-+}
-+
-+
-+// n must be > 0 on entry
-+#define get_cabac_sig_coeff_flag_idxs get_cabac_sig_coeff_flag_idxs_arm
-+static inline uint8_t * get_cabac_sig_coeff_flag_idxs_arm(CABACContext * const c, uint8_t * const state0,
-+ unsigned int n,
-+ const uint8_t const * ctx_map,
-+ uint8_t * p)
-+{
-+ unsigned int reg_b, tmp, st, bit;
-+ __asm__ (
-+ "1: \n\t"
-+// Get bin from map
-+ "ldrb %[st] , [%[ctx_map], %[n]] \n\t"
-+
-+// Load state & ranges
-+ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t"
-+ "ldrb %[bit] , [%[state0], %[st]] \n\t"
-+ "and %[tmp] , %[range] , #0xC0 \n\t"
-+ "add %[r_b] , %[r_b] , %[tmp], lsl #1 \n\t"
-+ "ldrb %[tmp] , [%[r_b], %[bit]] \n\t"
-+ "sub %[range] , %[range] , %[tmp] \n\t"
-+
-+ "cmp %[low] , %[range], lsl #17 \n\t"
-+ "ittt ge \n\t"
-+ "subge %[low] , %[low] , %[range], lsl #17 \n\t"
-+ "mvnge %[bit] , %[bit] \n\t"
-+ "movge %[range] , %[tmp] \n\t"
-+
-+ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t"
-+ "tst %[bit] , #1 \n\t"
-+// GCC asm seems to need strbne written differently for thumb and arm
-+#if CONFIG_THUMB
-+ "it ne \n\t"
-+ "strbne %[n] , [%[idx]] , #1 \n\t"
-+#else
-+ "strneb %[n] , [%[idx]] , #1 \n\t"
-+#endif
-+
-+// Renorm
-+ "clz %[tmp] , %[range] \n\t"
-+ "sub %[tmp] , #23 \n\t"
-+ "lsl %[low] , %[low] , %[tmp] \n\t"
-+ "lsl %[range] , %[range] , %[tmp] \n\t"
-+
-+ "strb %[r_b] , [%[state0], %[st]] \n\t"
-+// There is a small speed gain from combining both conditions, using a single
-+// branch and then working out what that meant later
-+ "subs %[n] , %[n] , #1 \n\t"
-+#if CONFIG_THUMB
-+ "itt ne \n\t"
-+ "lslsne %[tmp] , %[low] , #16 \n\t"
-+ "bne 1b \n\t"
-+#else
-+ "lslnes %[tmp] , %[low] , #16 \n\t"
-+ "bne 1b \n\t"
-+#endif
-+
-+// If we have bits left then n must be 0 so give up now
-+ "lsls %[tmp] , %[low] , #16 \n\t"
-+ "bne 2f \n\t"
-+
-+// Do reload
-+ "ldrh %[tmp] , [%[bptr]] , #2 \n\t"
-+ "movw %[r_b] , #0xFFFF \n\t"
-+ "rev %[tmp] , %[tmp] \n\t"
-+ "rsb %[tmp] , %[r_b] , %[tmp], lsr #15 \n\t"
-+
-+ "rbit %[r_b] , %[low] \n\t"
-+ "clz %[r_b] , %[r_b] \n\t"
-+ "sub %[r_b] , %[r_b] , #16 \n\t"
-+
-+#if CONFIG_THUMB
-+ "lsl %[tmp] , %[tmp] , %[r_b] \n\t"
-+ "add %[low] , %[low] , %[tmp] \n\t"
-+#else
-+ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t"
-+#endif
-+
-+// Check to see if we still have more to do
-+ "cmp %[n] , #0 \n\t"
-+ "bne 1b \n\t"
-+ "2: \n\t"
-+ : [bit]"=&r"(bit),
-+ [low]"+&r"(c->low),
-+ [range]"+&r"(c->range),
-+ [r_b]"=&r"(reg_b),
-+ [bptr]"+&r"(c->bytestream),
-+ [idx]"+&r"(p),
-+ [n]"+&r"(n),
-+ [tmp]"=&r"(tmp),
-+ [st]"=&r"(st)
-+ : [state0]"r"(state0),
-+ [ctx_map]"r"(ctx_map),
-+ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128),
-+ [byte]"M"(offsetof(CABACContext, bytestream)),
-+ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET)
-+ : "memory", "cc"
-+ );
-+
-+ return p;
-+}
-+
-+// ---------------------------------------------------------------------------
-+//
-+// CABAC_BY22 functions
-+//
-+// By and large these are (at best) no faster than their C equivalents - the
-+// only one worth having is _peek where we do a slightly better job than the
-+// compiler
-+//
-+// The others have been stashed here for reference in case larger scale asm
-+// is attempted in which case they might be a useful base
-+
-+
-+#define get_cabac_by22_peek get_cabac_by22_peek_arm
-+static inline uint32_t get_cabac_by22_peek_arm(const CABACContext *const c)
-+{
-+ uint32_t rv, tmp;
-+ __asm__ (
-+ "bic %[rv] , %[low], #1 \n\t"
-+ "cmp %[inv] , #0 \n\t"
-+ "it ne \n\t"
-+ "umullne %[tmp] , %[rv] , %[inv], %[rv] \n\t"
-+ : // Outputs
-+ [rv]"=&r"(rv),
-+ [tmp]"=r"(tmp)
-+ : // Inputs
-+ [low]"r"(c->low),
-+ [inv]"r"(c->range)
-+ : // Clobbers
-+ "cc"
-+ );
-+ return rv << 1;
-+}
-+
-+#if 0
-+
-+// ***** Slower than the C :-(
-+#define get_cabac_by22_flush get_cabac_by22_flush_arm
-+static inline void get_cabac_by22_flush_arm(CABACContext *const c, const unsigned int n, const uint32_t val)
-+{
-+ uint32_t m, tmp;
-+ __asm__ (
-+ "add %[bits], %[bits], %[n] \n\t"
-+ "ldr %[m], [%[ptr], %[bits], lsr #3] \n\t"
-+
-+ "rsb %[tmp], %[n], #32 \n\t"
-+ "lsr %[tmp], %[val], %[tmp] \n\t"
-+ "mul %[tmp], %[range], %[tmp] \n\t"
-+
-+ "rev %[m], %[m] \n\t"
-+
-+ "lsl %[tmp], %[tmp], #23 \n\t"
-+ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t"
-+
-+ "and %[tmp], %[bits], #7 \n\t"
-+ "lsl %[m], %[m], %[tmp] \n\t"
-+
-+ "orr %[low], %[low], %[m], lsr #9 \n\t"
-+ : // Outputs
-+ [m]"=&r"(m),
-+ [tmp]"=&r"(tmp),
-+ [bits]"+&r"(c->by22.bits),
-+ [low]"+&r"(c->low)
-+ : // Inputs
-+ [n]"r"(n),
-+ [val]"r"(val),
-+ [inv]"r"(c->range),
-+ [range]"r"(c->by22.range),
-+ [ptr]"r"(c->bytestream)
-+ : // Clobbers
-+ );
-+}
-+
-+
-+// Works but slower than C
-+#define coeff_abs_level_remaining_decode_by22(c,r) coeff_abs_level_remaining_decode_by22_arm(c, r)
-+static int coeff_abs_level_remaining_decode_by22_arm(CABACContext * const c, const unsigned int c_rice_param)
-+{
-+ uint32_t n, val, tmp, level;
-+
-+// PROFILE_START();
-+
-+ __asm__ (
-+ // Peek
-+ "bic %[val], %[low], #1 \n\t"
-+ "cmp %[inv], #0 \n\t"
-+ "umullne %[tmp], %[val], %[inv], %[val] \n\t"
-+ "lsl %[val], %[val], #1 \n\t"
-+
-+ // Count bits (n = prefix)
-+ "mvn %[n], %[val] \n\t"
-+ "clz %[n], %[n] \n\t"
-+
-+ "lsl %[level], %[val], %[n] \n\t"
-+ "subs %[tmp], %[n], #3 \n\t"
-+ "blo 2f \n\t"
-+
-+ // prefix >= 3
-+ // < tmp = prefix - 3
-+ // > tmp = prefix + rice - 3
-+ "add %[tmp], %[tmp], %[rice] \n\t"
-+ // > n = prefix * 2 + rice - 3
-+ "add %[n], %[tmp], %[n] \n\t"
-+ "cmp %[n], #21 \n\t"
-+ "bhi 3f \n\t"
-+
-+ "orr %[level], %[level], #0x80000000 \n\t"
-+ "rsb %[tmp], %[tmp], #31 \n\t"
-+ "lsr %[level], %[level], %[tmp] \n\t"
-+
-+ "mov %[tmp], #2 \n\t"
-+ "add %[level], %[level], %[tmp], lsl %[rice] \n\t"
-+ "b 1f \n\t"
-+
-+ // > 22 bits used in total - need reload
-+ "3: \n\t"
-+
-+ // Stash prefix + rice - 3 in level (only spare reg)
-+ "mov %[level], %[tmp] \n\t"
-+ // Restore n to flush value (prefix)
-+ "sub %[n], %[n], %[tmp] \n\t"
-+
-+ // Flush + reload
-+
-+// "rsb %[tmp], %[n], #32 \n\t"
-+// "lsr %[tmp], %[val], %[tmp] \n\t"
-+// "mul %[tmp], %[range], %[tmp] \n\t"
-+
-+ // As it happens we know that all the bits we are flushing are 1
-+ // so we can cheat slightly
-+ "rsb %[tmp], %[range], %[range], lsl %[n] \n\t"
-+ "lsl %[tmp], %[tmp], #23 \n\t"
-+ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t"
-+
-+ "add %[bits], %[bits], %[n] \n\t"
-+ "ldr %[n], [%[ptr], %[bits], lsr #3] \n\t"
-+ "rev %[n], %[n] \n\t"
-+ "and %[tmp], %[bits], #7 \n\t"
-+ "lsl %[n], %[n], %[tmp] \n\t"
-+
-+ "orr %[low], %[low], %[n], lsr #9 \n\t"
-+
-+ // (reload)
-+
-+ "bic %[val], %[low], #1 \n\t"
-+ "cmp %[inv], #0 \n\t"
-+ "umullne %[tmp], %[val], %[inv], %[val] \n\t"
-+ "lsl %[val], %[val], #1 \n\t"
-+
-+ // Build value
-+
-+ "mov %[n], %[level] \n\t"
-+
-+ "orr %[tmp], %[val], #0x80000000 \n\t"
-+ "rsb %[level], %[level], #31 \n\t"
-+ "lsr %[level], %[tmp], %[level] \n\t"
-+
-+ "mov %[tmp], #2 \n\t"
-+ "add %[level], %[level], %[tmp], lsl %[rice] \n\t"
-+ "b 1f \n\t"
-+
-+ // prefix < 3
-+ "2: \n\t"
-+ "rsb %[tmp], %[rice], #31 \n\t"
-+ "lsr %[level], %[level], %[tmp] \n\t"
-+ "orr %[level], %[level], %[n], lsl %[rice] \n\t"
-+ "add %[n], %[n], %[rice] \n\t"
-+
-+ "1: \n\t"
-+ // Flush
-+ "add %[n], %[n], #1 \n\t"
-+
-+ "rsb %[tmp], %[n], #32 \n\t"
-+ "lsr %[tmp], %[val], %[tmp] \n\t"
-+
-+ "add %[bits], %[bits], %[n] \n\t"
-+ "ldr %[val], [%[ptr], %[bits], lsr #3] \n\t"
-+
-+ "mul %[tmp], %[range], %[tmp] \n\t"
-+ "lsl %[tmp], %[tmp], #23 \n\t"
-+ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t"
-+
-+ "rev %[val], %[val] \n\t"
-+ "and %[tmp], %[bits], #7 \n\t"
-+ "lsl %[val], %[val], %[tmp] \n\t"
-+
-+ "orr %[low], %[low], %[val], lsr #9 \n\t"
-+ : // Outputs
-+ [level]"=&r"(level),
-+ [n]"=&r"(n),
-+ [val]"=&r"(val),
-+ [tmp]"=&r"(tmp),
-+ [bits]"+&r"(c->by22.bits),
-+ [low]"+&r"(c->low)
-+ : // Inputs
-+ [rice]"r"(c_rice_param),
-+ [inv]"r"(c->range),
-+ [range]"r"(c->by22.range),
-+ [ptr]"r"(c->bytestream)
-+ : // Clobbers
-+ "cc"
-+ );
-+
-+// PROFILE_ACC(residual_abs);
-+
-+ return level;
-+}
-+#endif
-+
-+#endif /* HAVE_ARMV6T2_INLINE */
-+
-+#endif /* AVCODEC_ARM_HEVC_CABAC_H */
-diff --git a/libavcodec/arm/hevcdsp_deblock_neon.S b/libavcodec/arm/hevcdsp_deblock_neon.S
-index bad4589..a088cc3 100644
---- a/libavcodec/arm/hevcdsp_deblock_neon.S
-+++ b/libavcodec/arm/hevcdsp_deblock_neon.S
-@@ -409,10 +409,12 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
- beq 90f
-
- tst a3, #1
-+ itee ne
- ldrne a3, [v5, #0] @ curr->mv[0]
- ldreq a3, [v5, #4] @ curr->mv[1]
- moveq v1, v2
- tst v8, #1
-+ itee ne
- ldrne v8, [v6, #0] @ neigh->mv[0]
- ldreq v8, [v6, #4] @ neigh->mv[1]
- moveq v3, v4
-@@ -424,9 +426,14 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
- sel a3, a3, ip
- ands a3, a3, lr
- @ drop through
--10: movne a3, #1
-+10: it ne
-+ movne a3, #1
- 11: subs a2, a2, #1
--12: strbhs a3, [v7], a4
-+12:
-+A strbhs a3, [v7], a4
-+T itt hs
-+T strbhs a3, [v7]
-+T addhs v7, v7, a4
- subs a2, a2, #1
- bhs 12b
-
-@@ -442,6 +449,7 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
- bne 10b
-
- teq v1, v3
-+ it eq
- teqeq v2, v4
- bne 40f
- teq v1, v2
-@@ -487,6 +495,7 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
- b 10b
-
- 40: teq v1, v4
-+ ite eq
- teqeq v2, v3
- bne 10b
-
-diff --git a/libavcodec/arm/hevcdsp_epel_neon.S b/libavcodec/arm/hevcdsp_epel_neon.S
-index 516ae5b..00eab9e 100644
---- a/libavcodec/arm/hevcdsp_epel_neon.S
-+++ b/libavcodec/arm/hevcdsp_epel_neon.S
-@@ -110,7 +110,9 @@ function ff_hevc_put_epel_h_neon_8, export=1
- sub r7, #1
- lsl r7, #2
- vpush {d8-d15}
-- adrl r12, epel_coeffs
-+@ adr reaches if we are in thumb mode but not in arm
-+T adr r12, epel_coeffs
-+A adrl r12, epel_coeffs
- add r7, r12
- sub r1, #1
- lsl r4, #1
-@@ -170,7 +172,8 @@ function ff_hevc_put_epel_v_neon_8, export=1
- sub r7, #1
- lsl r7, #2
- vpush {d8-d15}
-- adrl r12, epel_coeffs
-+T adr r12, epel_coeffs
-+A adrl r12, epel_coeffs
- add r7, r12
- load_coeffs_16b r7
- sub r1, r2
-@@ -246,7 +249,7 @@ function ff_hevc_put_epel_hv_neon_8, export=1
- sub r7, #1
- lsl r7, #2
- vpush {d8-d15}
-- adrl r12, epel_coeffs
-+ adr r12, epel_coeffs
- sub r6, #1
- lsl r6, #2
- add r6, r12 // mx epel coeff offset
-diff --git a/libavcodec/cabac.c b/libavcodec/cabac.c
-index f298336..91f5ef5 100644
---- a/libavcodec/cabac.c
-+++ b/libavcodec/cabac.c
-@@ -59,10 +59,19 @@ int ff_init_cabac_decoder(CABACContext *c, const uint8_t *buf, int buf_size){
- #if CABAC_BITS == 16
- c->low = (*c->bytestream++)<<18;
- c->low+= (*c->bytestream++)<<10;
-+ // Keep our fetches on a 2-byte boundry as this should avoid ever having to
-+ // do unaligned loads if the compiler (or asm) optimises the double byte
-+ // load into a single instruction
-+ if(((uintptr_t)c->bytestream & 1) == 0) {
-+ c->low += (1 << 9);
-+ }
-+ else {
-+ c->low += ((*c->bytestream++) << 2) + 2;
-+ }
- #else
- c->low = (*c->bytestream++)<<10;
+ #include "config.h"
+@@ -80,9 +80,7 @@
+ #include
+ #include
+ #include
+-#ifdef RPI_ZERO_COPY
+-#include "libavcodec/rpi_qpu.h"
-#endif
- c->low+= ((*c->bytestream++)<<2) + 2;
-+#endif
- c->range= 0x1FE;
- if ((c->range<<(CABAC_BITS+1)) < c->low)
- return AVERROR_INVALIDDATA;
-diff --git a/libavcodec/cabac.h b/libavcodec/cabac.h
-index 857211c..857a1de 100644
---- a/libavcodec/cabac.h
-+++ b/libavcodec/cabac.h
-@@ -48,7 +48,14 @@ extern CABAC_TABLE_CONST uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63];
- typedef struct CABACContext{
- int low;
- int range;
-- int outstanding_count;
-+ union
-+ {
-+ int outstanding_count;
-+ struct {
-+ uint16_t bits;
-+ uint16_t range;
-+ } by22;
-+ };
- const uint8_t *bytestream_start;
- const uint8_t *bytestream;
- const uint8_t *bytestream_end;
-diff --git a/libavcodec/cabac_functions.h b/libavcodec/cabac_functions.h
-index 2d1d2a6..d3518cb 100644
---- a/libavcodec/cabac_functions.h
-+++ b/libavcodec/cabac_functions.h
-@@ -51,6 +51,7 @@ static CABAC_TABLE_CONST uint8_t * const ff_h264_lps_range = ff_h264_cabac_table
- static CABAC_TABLE_CONST uint8_t * const ff_h264_mlps_state = ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET;
- static CABAC_TABLE_CONST uint8_t * const ff_h264_last_coeff_flag_offset_8x8 = ff_h264_cabac_tables + H264_LAST_COEFF_FLAG_OFFSET_8x8_OFFSET;
-
-+#if !defined(get_cabac_bypass) || !defined(get_cabac_terminate)
- static void refill(CABACContext *c){
- #if CABAC_BITS == 16
- c->low+= (c->bytestream[0]<<9) + (c->bytestream[1]<<1);
-@@ -63,7 +64,9 @@ static void refill(CABACContext *c){
++#include "libavcodec/rpi_zc.h"
#endif
- c->bytestream += CABAC_BITS / 8;
- }
-+#endif
-+#ifndef get_cabac_terminate
- static inline void renorm_cabac_decoder_once(CABACContext *c){
- int shift= (uint32_t)(c->range - 0x100)>>31;
- c->range<<= shift;
-@@ -71,14 +74,18 @@ static inline void renorm_cabac_decoder_once(CABACContext *c){
- if(!(c->low & CABAC_MASK))
- refill(c);
- }
-+#endif
+ #if HAVE_SYS_RESOURCE_H
+@@ -183,13 +181,7 @@ static void free_input_threads(void);
- #ifndef get_cabac_inline
- static void refill2(CABACContext *c){
- int i;
- unsigned x;
+ static MMAL_COMPONENT_T* rpi_display = NULL;
+ static MMAL_POOL_T *rpi_pool = NULL;
-
-+#if !HAVE_FAST_CLZ
- x= c->low ^ (c->low-1);
- i= 7 - ff_h264_norm_shift[x>>(CABAC_BITS-1)];
-+#else
-+ i = ff_ctz(c->low) - CABAC_BITS;
-+#endif
+-#ifdef RPI_ZERO_COPY
+-static uint8_t *get_vc_handle(AVBufferRef *bref) {
+- GPU_MEM_PTR_T *p = av_buffer_pool_opaque(bref);
+- return (uint8_t *)p->vc_handle;
+-}
+-#endif
++static volatile int rpi_display_count = 0;
- x= -CABAC_MASK;
-
-@@ -94,7 +101,9 @@ static void refill2(CABACContext *c){
- #endif
- c->bytestream += CABAC_BITS/8;
- }
-+#endif
-
-+#ifndef get_cabac_inline
- static av_always_inline int get_cabac_inline(CABACContext *c, uint8_t * const state){
- int s = *state;
- int RangeLPS= ff_h264_lps_range[2*(c->range&0xC0) + s];
-@@ -166,6 +175,7 @@ static av_always_inline int get_cabac_bypass_sign(CABACContext *c, int val){
- *
- * @return the number of bytes read or 0 if no end
- */
-+#ifndef get_cabac_terminate
- static int av_unused get_cabac_terminate(CABACContext *c){
- c->range -= 2;
- if(c->low < c->range<<(CABAC_BITS+1)){
-@@ -175,11 +185,13 @@ static int av_unused get_cabac_terminate(CABACContext *c){
- return c->bytestream - c->bytestream_start;
+ static MMAL_POOL_T* display_alloc_pool(MMAL_PORT_T* port, size_t w, size_t h)
+ {
+@@ -206,7 +198,7 @@ static MMAL_POOL_T* display_alloc_pool(MMAL_PORT_T* port, size_t w, size_t h)
+ for (i = 0; i < NUM_BUFFERS; ++i)
+ {
+ MMAL_BUFFER_HEADER_T* buffer = pool->header[i];
+- void* bufPtr = buffer->data;
++ char * bufPtr = buffer->data;
+ memset(bufPtr, i*30, w*h);
+ memset(bufPtr+w*h, 128, (w*h)/2);
}
+@@ -215,23 +207,31 @@ static MMAL_POOL_T* display_alloc_pool(MMAL_PORT_T* port, size_t w, size_t h)
+ return pool;
}
+
+-static void display_cb_input(MMAL_PORT_T *port,MMAL_BUFFER_HEADER_T *buffer) {
++static void display_cb_input(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer) {
++#ifdef RPI_ZERO_COPY
++ av_rpi_zc_unref(buffer->user_data);
++ --rpi_display_count;
+#endif
-
- /**
- * Skip @p n bytes and reset the decoder.
- * @return the address of the first skipped byte or NULL if there's less than @p n bytes left
- */
-+#ifndef skip_bytes
- static av_unused const uint8_t* skip_bytes(CABACContext *c, int n) {
- const uint8_t *ptr = c->bytestream;
-
-@@ -196,5 +208,6 @@ static av_unused const uint8_t* skip_bytes(CABACContext *c, int n) {
-
- return ptr;
++ mmal_buffer_header_release(buffer);
++}
++
++static void display_cb_control(MMAL_PORT_T *port,MMAL_BUFFER_HEADER_T *buffer) {
+ mmal_buffer_header_release(buffer);
}
+
+ static MMAL_COMPONENT_T* display_init(size_t x, size_t y, size_t w, size_t h)
+ {
+ MMAL_COMPONENT_T* display;
+- int w2 = (w+31)&~31;
+- int h2 = (h+15)&~15;
+ MMAL_DISPLAYREGION_T region =
+ {
+- {MMAL_PARAMETER_DISPLAYREGION, sizeof(region)},
++ .hdr = {MMAL_PARAMETER_DISPLAYREGION, sizeof(region)},
+ .set = MMAL_DISPLAY_SET_LAYER | MMAL_DISPLAY_SET_FULLSCREEN | MMAL_DISPLAY_SET_DEST_RECT,
+ .layer = 2,
+ .fullscreen = 0,
+ .dest_rect = {x, y, w, h}
+ };
++ const AVRpiZcFrameGeometry geo = av_rpi_zc_frame_geometry(w, h);
++
+ bcm_host_init(); // TODO is this needed?
+ mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &display);
+ assert(display);
+@@ -240,8 +240,8 @@ static MMAL_COMPONENT_T* display_init(size_t x, size_t y, size_t w, size_t h)
+
+ MMAL_ES_FORMAT_T* format = display->input[0]->format;
+ format->encoding = MMAL_ENCODING_I420;
+- format->es->video.width = w2;
+- format->es->video.height = h2;
++ format->es->video.width = geo.stride_y;
++ format->es->video.height = geo.height_y;
+ format->es->video.crop.x = 0;
+ format->es->video.crop.y = 0;
+ format->es->video.crop.width = w;
+@@ -250,46 +250,75 @@ static MMAL_COMPONENT_T* display_init(size_t x, size_t y, size_t w, size_t h)
+
+ mmal_component_enable(display);
+
+- rpi_pool = display_alloc_pool(display->input[0], w2, h2);
++ rpi_pool = display_alloc_pool(display->input[0], geo.stride_y, geo.height_y);
+
+ mmal_port_enable(display->input[0],display_cb_input);
+- mmal_port_enable(display->control,display_cb_input);
++ mmal_port_enable(display->control,display_cb_control);
+
+- printf("Allocated display %d %d\n",w,h);
++ printf("Allocated display %dx%d in %dx%d\n", w, h, geo.stride_y, geo.height_y);
+
+ return display;
+ }
+
+-static void display_frame(MMAL_COMPONENT_T* display,AVFrame* fr)
++static void display_frame(struct AVCodecContext * const s, MMAL_COMPONENT_T* const display, const AVFrame* const fr)
+ {
+- int w = fr->width;
+- int h = fr->height;
+- int w2 = (w+31)&~31;
+- int h2 = (h+15)&~15;
+ if (!display || !rpi_pool)
+ return;
++
++ if (rpi_display_count >= 3) {
++ av_log(s, AV_LOG_VERBOSE, "Frame dropped\n");
++ return;
++ }
++
+ MMAL_BUFFER_HEADER_T* buf = mmal_queue_get(rpi_pool->queue);
+ if (!buf) {
+- // Running too fast so drop the frame
+- return;
++ // Running too fast so drop the frame
++ printf("Q alloc failure\n");
++ return;
+ }
+ assert(buf);
+ buf->cmd = 0;
+- buf->length = (w2 * h2 * 3)/2;
+ buf->offset = 0; // Offset to valid data
+ buf->flags = 0;
+ #ifdef RPI_ZERO_COPY
+- buf->data = get_vc_handle(fr->buf[0]);
+- buf->alloc_size = (w2*h2*3)/2;
++{
++ const AVRpiZcRefPtr fr_buf = av_rpi_zc_ref(s, fr, 1);
++
++ buf->user_data = fr_buf;
++ buf->data = av_rpi_zc_vc_handle(fr_buf);
++ buf->alloc_size =
++ buf->length = av_rpi_zc_numbytes(fr_buf);
++
++ ++rpi_display_count;
++}
+ #else
++{
++#error YYY
++ int w = fr->width;
++ int h = fr->height;
++ int w2 = (w+31)&~31;
++ int h2 = (h+15)&~15;
++
++ buf->length = (w2 * h2 * 3)/2;
++ buf->user_data = NULL;
++
+ //mmal_buffer_header_mem_lock(buf);
+ memcpy(buf->data, fr->data[0], w2 * h);
+ memcpy(buf->data+w2*h2, fr->data[1], w2 * h / 4);
+ memcpy(buf->data+w2*h2*5/4, fr->data[2], w2 * h / 4);
+ //mmal_buffer_header_mem_unlock(buf);
++}
+ #endif
+
+- mmal_port_send_buffer(display->input[0], buf); // I assume this will automatically get released
++ while (rpi_display_count >= 3) {
++ usleep(5000);
++ }
++
++ if (mmal_port_send_buffer(display->input[0], buf) != MMAL_SUCCESS)
++ {
++ printf("** send failed: depth=%d\n", rpi_display_count);
++ display_cb_input(NULL, buf);
++ }
+ }
+
+ static void display_exit(MMAL_COMPONENT_T* display)
+@@ -687,6 +716,11 @@ static void ffmpeg_cleanup(int ret)
+ avformat_close_input(&input_files[i]->ctx);
+ av_freep(&input_files[i]);
+ }
++
++#ifdef RPI_DISPLAY
++ display_exit(rpi_display);
+#endif
++
+ for (i = 0; i < nb_input_streams; i++) {
+ InputStream *ist = input_streams[i];
- #endif /* AVCODEC_CABAC_FUNCTIONS_H */
-diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c
-index 271e17a..4caf720 100644
---- a/libavcodec/hevc_cabac.c
-+++ b/libavcodec/hevc_cabac.c
-@@ -21,14 +21,72 @@
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
+@@ -698,6 +732,9 @@ static void ffmpeg_cleanup(int ret)
+ av_freep(&ist->filters);
+ av_freep(&ist->hwaccel_device);
-+#define UNCHECKED_BITSTREAM_READER 1
-+
- #include "libavutil/attributes.h"
- #include "libavutil/common.h"
-
--#include "cabac_functions.h"
- #include "hevc.h"
-+#include "cabac_functions.h"
-+
-+// BY22 is probably faster than simple bypass if the processor has
-+// either a fast 32-bit divide or a fast 32x32->64[63:32] instruction
-+// x86 has fast int divide
-+// Arm doesn't have divide or general fast 64 bit, but does have the multiply
-+// * Beware: ARCH_xxx isn't set if configure --disable-asm is used
-+#define USE_BY22 (HAVE_FAST_64BIT || ARCH_ARM || ARCH_X86)
-+// Use native divide if we have a fast one - otherwise use mpy 1/x
-+// x86 has a fast integer divide - arm doesn't - unsure about other
-+// architectures
-+#define USE_BY22_DIV ARCH_X86
-+
-+// Special case blocks with a single significant ceoff
-+// Decreases the complexity of the code for a common case but increases the
-+// code size.
-+#define USE_N_END_1 1
-+
-+#if ARCH_ARM
-+#include "arm/hevc_cabac.h"
++#ifdef RPI_ZERO_COPY
++ av_rpi_zc_uninit(ist->dec_ctx);
+#endif
+ avcodec_free_context(&ist->dec_ctx);
- #define CABAC_MAX_BIN 31
+ av_freep(&input_streams[i]);
+@@ -729,9 +766,6 @@ static void ffmpeg_cleanup(int ret)
+ term_exit();
+ ffmpeg_exited = 1;
+-#ifdef RPI_DISPLAY
+- display_exit(rpi_display);
+-#endif
+ }
+
+ void remove_avoptions(AVDictionary **a, AVDictionary *b)
+@@ -1079,18 +1113,19 @@ static void do_video_out(AVFormatContext *s,
+ int frame_size = 0;
+ InputStream *ist = NULL;
+ AVFilterContext *filter = ost->filter->filter;
+
-+#if USE_BY22 && !USE_BY22_DIV
-+#define I(x) (uint32_t)((0x10000000000ULL / (uint64_t)(x)) + 1ULL)
++ if (ost->source_index >= 0)
++ ist = input_streams[ost->source_index];
+
-+static const uint32_t cabac_by22_inv_range[256] = {
-+ 0, I(257), I(258), I(259),
-+ I(260), I(261), I(262), I(263), I(264), I(265), I(266), I(267), I(268), I(269),
-+ I(270), I(271), I(272), I(273), I(274), I(275), I(276), I(277), I(278), I(279),
-+ I(280), I(281), I(282), I(283), I(284), I(285), I(286), I(287), I(288), I(289),
-+ I(290), I(291), I(292), I(293), I(294), I(295), I(296), I(297), I(298), I(299),
-+ I(300), I(301), I(302), I(303), I(304), I(305), I(306), I(307), I(308), I(309),
-+ I(310), I(311), I(312), I(313), I(314), I(315), I(316), I(317), I(318), I(319),
-+ I(320), I(321), I(322), I(323), I(324), I(325), I(326), I(327), I(328), I(329),
-+ I(330), I(331), I(332), I(333), I(334), I(335), I(336), I(337), I(338), I(339),
-+ I(340), I(341), I(342), I(343), I(344), I(345), I(346), I(347), I(348), I(349),
-+ I(350), I(351), I(352), I(353), I(354), I(355), I(356), I(357), I(358), I(359),
-+ I(360), I(361), I(362), I(363), I(364), I(365), I(366), I(367), I(368), I(369),
-+ I(370), I(371), I(372), I(373), I(374), I(375), I(376), I(377), I(378), I(379),
-+ I(380), I(381), I(382), I(383), I(384), I(385), I(386), I(387), I(388), I(389),
-+ I(390), I(391), I(392), I(393), I(394), I(395), I(396), I(397), I(398), I(399),
-+ I(400), I(401), I(402), I(403), I(404), I(405), I(406), I(407), I(408), I(409),
-+ I(410), I(411), I(412), I(413), I(414), I(415), I(416), I(417), I(418), I(419),
-+ I(420), I(421), I(422), I(423), I(424), I(425), I(426), I(427), I(428), I(429),
-+ I(430), I(431), I(432), I(433), I(434), I(435), I(436), I(437), I(438), I(439),
-+ I(440), I(441), I(442), I(443), I(444), I(445), I(446), I(447), I(448), I(449),
-+ I(450), I(451), I(452), I(453), I(454), I(455), I(456), I(457), I(458), I(459),
-+ I(460), I(461), I(462), I(463), I(464), I(465), I(466), I(467), I(468), I(469),
-+ I(470), I(471), I(472), I(473), I(474), I(475), I(476), I(477), I(478), I(479),
-+ I(480), I(481), I(482), I(483), I(484), I(485), I(486), I(487), I(488), I(489),
-+ I(490), I(491), I(492), I(493), I(494), I(495), I(496), I(497), I(498), I(499),
-+ I(500), I(501), I(502), I(503), I(504), I(505), I(506), I(507), I(508), I(509),
-+ I(510), I(511)
-+};
-+#undef I
-+#endif // USE_BY22
+ #ifdef RPI_DISPLAY
+- if (next_picture)
++ if (next_picture && ist != NULL)
+ {
+- if (!rpi_display)
++ if (!rpi_display)
+ rpi_display = display_init(0,0,next_picture->width,next_picture->height);
+- display_frame(rpi_display,next_picture);
++ display_frame(ist->dec_ctx, rpi_display, next_picture);
+ }
+ #endif
+
+- if (ost->source_index >= 0)
+- ist = input_streams[ost->source_index];
+-
+ if (filter->inputs[0]->frame_rate.num > 0 &&
+ filter->inputs[0]->frame_rate.den > 0)
+ duration = 1/(av_q2d(filter->inputs[0]->frame_rate) * av_q2d(enc->time_base));
+@@ -2692,6 +2727,12 @@ static int init_input_stream(int ist_index, char *error, int error_len)
+ ist->dec_ctx->opaque = ist;
+ ist->dec_ctx->get_format = get_format;
+ ist->dec_ctx->get_buffer2 = get_buffer;
+
- /**
- * number of bin by SyntaxElement.
- */
-@@ -445,6 +503,211 @@ static const uint8_t diag_scan8x8_inv[8][8] = {
- { 28, 36, 43, 49, 54, 58, 61, 63, },
++#ifdef RPI_ZERO_COPY
++ // Overrides the above get_buffer2
++ av_rpi_zc_init(ist->dec_ctx);
++#endif
++
+ ist->dec_ctx->thread_safe_callbacks = 1;
+
+ av_opt_set_int(ist->dec_ctx, "refcounted_frames", 1, 0);
+diff --git a/libavcodec/Makefile b/libavcodec/Makefile
+index 0fd6767..bae3f2d 100644
+--- a/libavcodec/Makefile
++++ b/libavcodec/Makefile
+@@ -9,6 +9,7 @@ HEADERS = avcodec.h \
+ rpi_shader.h \
+ rpi_mailbox.h \
+ rpi_hevc_transform.h \
++ rpi_zc.h \
+ dv_profile.h \
+ d3d11va.h \
+ dirac.h \
+@@ -46,6 +47,7 @@ OBJS = allcodecs.o \
+ rpi_qpu.o \
+ rpi_shader.o \
+ rpi_mailbox.o \
++ rpi_zc.o \
+ vorbis_parser.o \
+ xiph.o \
+
+diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
+index d849765..b934740 100644
+--- a/libavcodec/avcodec.h
++++ b/libavcodec/avcodec.h
+@@ -3355,6 +3355,12 @@ typedef struct AVCodecContext {
+ AVPacketSideData *coded_side_data;
+ int nb_coded_side_data;
+
++ /**
++ * Opaque pointer for use by replacement get_buffer2 code
++ *
++ * @author jc (08/02/2016)
++ */
++ void * get_buffer_context;
+ } AVCodecContext;
+
+ AVRational av_codec_get_pkt_timebase (const AVCodecContext *avctx);
+diff --git a/libavcodec/hevc.c b/libavcodec/hevc.c
+index 35a1394..001c9e8 100644
+--- a/libavcodec/hevc.c
++++ b/libavcodec/hevc.c
+@@ -114,10 +114,6 @@ static uint32_t rpi_filter_coefs[8][1] = {
+ { ENCODE_COEFFS( -2, 10, 58, -2) }
};
-+
-+typedef struct
-+{
-+ uint16_t coeff;
-+ uint16_t scale;
-+} xy_off_t;
-+
-+#define XYT_C(x,y,t) ((x) + ((y) << (t)))
-+#define SCALE_TRAFO(t) ((t) > 3 ? 3 : (t))
-+#define SCALE_SHR(t) ((t) - SCALE_TRAFO(t))
-+#define XYT_S(x,y,t) (((x) >> SCALE_SHR(t)) + (((y) >> SCALE_SHR(t)) << SCALE_TRAFO(t)))
-+
-+#define XYT(x,y,t) {XYT_C(x,y,t), XYT_S(x,y,t)}
-+
-+#define OFF_DIAG(t) {\
-+ XYT(0,0,t), XYT(0,1,t), XYT(1,0,t), XYT(0,2,t),\
-+ XYT(1,1,t), XYT(2,0,t), XYT(0,3,t), XYT(1,2,t),\
-+ XYT(2,1,t), XYT(3,0,t), XYT(1,3,t), XYT(2,2,t),\
-+ XYT(3,1,t), XYT(2,3,t), XYT(3,2,t), XYT(3,3,t)\
-+}
-+
-+#define OFF_HORIZ(t) {\
-+ XYT(0,0,t), XYT(1,0,t), XYT(2,0,t), XYT(3,0,t),\
-+ XYT(0,1,t), XYT(1,1,t), XYT(2,1,t), XYT(3,1,t),\
-+ XYT(0,2,t), XYT(1,2,t), XYT(2,2,t), XYT(3,2,t),\
-+ XYT(0,3,t), XYT(1,3,t), XYT(2,3,t), XYT(3,3,t)\
-+}
-+
-+#define OFF_VERT(t) {\
-+ XYT(0,0,t), XYT(0,1,t), XYT(0,2,t), XYT(0,3,t),\
-+ XYT(1,0,t), XYT(1,1,t), XYT(1,2,t), XYT(1,3,t),\
-+ XYT(2,0,t), XYT(2,1,t), XYT(2,2,t), XYT(2,3,t),\
-+ XYT(3,0,t), XYT(3,1,t), XYT(3,2,t), XYT(3,3,t)\
-+}
-+
-+static const xy_off_t off_xys[3][4][16] =
-+{
-+ {OFF_DIAG(2), OFF_DIAG(3), OFF_DIAG(4), OFF_DIAG(5)},
-+ {OFF_HORIZ(2), OFF_HORIZ(3), OFF_HORIZ(4), OFF_HORIZ(5)},
-+ {OFF_VERT(2), OFF_VERT(3), OFF_VERT(4), OFF_VERT(5)}
-+};
-+
-+
-+// Helper fns
-+#ifndef hevc_mem_bits32
-+static av_always_inline uint32_t hevc_mem_bits32(const void * buf, const unsigned int offset)
-+{
-+ return AV_RB32((const uint8_t *)buf + (offset >> 3)) << (offset & 7);
-+}
-+#endif
-+
-+#if AV_GCC_VERSION_AT_LEAST(3,4) && !defined(hevc_clz32)
-+#define hevc_clz32 hevc_clz32_builtin
-+static av_always_inline unsigned int hevc_clz32_builtin(const uint32_t x)
-+{
-+ // __builtin_clz says it works on ints - so adjust if int is >32 bits long
-+ return __builtin_clz(x) - (sizeof(int) * 8 - 32);
-+}
-+#endif
-+
-+// It is unlikely that we will ever need this but include for completeness
-+#ifndef hevc_clz32
-+static inline unsigned int hevc_clz32(unsigned int x)
-+{
-+ unsigned int n = 1;
-+ if ((x & 0xffff0000) == 0) {
-+ n += 16;
-+ x <<= 16;
-+ }
-+ if ((x & 0xff000000) == 0) {
-+ n += 8;
-+ x <<= 8;
-+ }
-+ if ((x & 0xf0000000) == 0) {
-+ n += 4;
-+ x <<= 4;
-+ }
-+ if ((x & 0xc0000000) == 0) {
-+ n += 2;
-+ x <<= 2;
-+ }
-+ return n - ((x >> 31) & 1);
-+}
-+#endif
-+
-+
-+#if !USE_BY22
-+// If no by22 then _by22 functions will revert to normal and so _peek/_flush
-+// will no longer be called but the setup calls will still exist and we want
-+// to null them out
-+#define bypass_start(s)
-+#define bypass_finish(s)
-+#else
-+// Use BY22 for residual bypass block
-+
-+#define bypass_start(s) get_cabac_by22_start(&s->HEVClc->cc)
-+#define bypass_finish(s) get_cabac_by22_finish(&s->HEVClc->cc)
-+
-+// BY22 notes that bypass is simply a divide into the bitstream and so we
-+// can peek out large quantities of bits at one and treat the result as if
-+// it was VLC. In many cases this will lead to O(1) processing rather than
-+// O(n) though the setup and teardown is sufficiently expensive that it is
-+// only worth using if we expect to be dealing with more than a few bits
-+// The definition of "a few bits" will vary from platform to platform but
-+// tests on ARM show that it probably isn't worth it for a single coded
-+// residual, but is for >1 - this is probaly reinforced that if there are
-+// more residuals then they are likely to be bigger and this will make the
-+// O(1) nature of the code more worthwhile.
-+
-+
-+#if !USE_BY22_DIV
-+// * 1/x @ 32 bits gets us 22 bits of accuracy
-+#define CABAC_BY22_PEEK_BITS 22
-+#else
-+// A real 32-bit divide gets us another bit
-+// If we have a 64 bit int & a unit time divider then we should get a lot
-+// of bits (55) but that is untested and it is unclear if it would give
-+// us a large advantage
-+#define CABAC_BY22_PEEK_BITS 23
-+#endif
-+
-+// Bypass block start
-+// Must be called before _by22_peek is used as it sets the CABAC environment
-+// into the correct state. _by22_finish must be called to return to 'normal'
-+// (i.e. non-bypass) cabac decoding
-+static inline void get_cabac_by22_start(CABACContext * const c)
-+{
-+ const unsigned int bits = __builtin_ctz(c->low);
-+ const uint32_t m = hevc_mem_bits32(c->bytestream, 0);
-+ uint32_t x = (c->low << (22 - CABAC_BITS)) ^ ((m ^ 0x80000000U) >> (9 + CABAC_BITS - bits));
-+#if !USE_BY22_DIV
-+ const uint32_t inv = cabac_by22_inv_range[c->range & 0xff];
-+#endif
-+
-+ c->bytestream -= (CABAC_BITS / 8);
-+ c->by22.bits = bits;
-+#if !USE_BY22_DIV
-+ c->by22.range = c->range;
-+ c->range = inv;
-+#endif
-+ c->low = x;
-+}
-+
-+// Bypass block finish
-+// Must be called at the end of the bypass block to return to normal operation
-+static inline void get_cabac_by22_finish(CABACContext * const c)
-+{
-+ unsigned int used = c->by22.bits;
-+ unsigned int bytes_used = (used / CABAC_BITS) * (CABAC_BITS / 8);
-+ unsigned int bits_used = used & (CABAC_BITS == 16 ? 15 : 7);
-+
-+ c->bytestream += bytes_used + (CABAC_BITS / 8);
-+ c->low = (((uint32_t)c->low >> (22 - CABAC_BITS + bits_used)) | 1) << bits_used;
-+#if !USE_BY22_DIV
-+ c->range = c->by22.range;
-+#endif
-+}
-+
-+// Peek bypass bits
-+// _by22_start must be called before _by22_peek is called and _by22_flush
-+// must be called afterwards to flush any used bits
-+// The actual number of valid bits returned is
-+// min(, CABAC_BY22_PEEK_BITS). CABAC_BY22_PEEK_BITS
-+// will be at least 22 which should be long enough for any prefix or suffix
-+// though probably not long enough for the worst case combination
-+#ifndef get_cabac_by22_peek
-+static inline uint32_t get_cabac_by22_peek(const CABACContext * const c)
-+{
-+#if USE_BY22_DIV
-+ return ((unsigned int)c->low / (unsigned int)c->range) << 9;
-+#else
-+ uint32_t x = c->low & ~1U;
-+ const uint32_t inv = c->range;
-+
-+ if (inv != 0)
-+ x = (uint32_t)(((uint64_t)x * (uint64_t)inv) >> 32);
-+
-+ return x << 1;
-+#endif
-+}
-+#endif
-+
-+// Flush bypass bits peeked by _by22_peek
-+// Flush n bypass bits. n must be >= 1 to guarantee correct operation
-+// val is an unmodified copy of whatever _by22_peek returned
-+#ifndef get_cabac_by22_flush
-+static inline void get_cabac_by22_flush(CABACContext * c, const unsigned int n, const uint32_t val)
-+{
-+ // Subtract the bits used & reshift up to the top of the word
-+#if USE_BY22_DIV
-+ const uint32_t low = (((unsigned int)c->low << n) - (((val >> (32 - n)) * (unsigned int)c->range) << 23));
-+#else
-+ const uint32_t low = (((uint32_t)c->low << n) - (((val >> (32 - n)) * c->by22.range) << 23));
-+#endif
-+
-+ // and refill lower bits
-+ // We will probably OR over some existing bits but that doesn't matter
-+ c->by22.bits += n;
-+ c->low = low | (hevc_mem_bits32(c->bytestream, c->by22.bits) >> 9);
-+}
-+#endif
-+
-+#endif // USE_BY22
-+
-+
- void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts)
- {
- if (s->ps.pps->entropy_coding_sync_enabled_flag &&
-@@ -863,19 +1126,19 @@ int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth)
- return GET_CABAC(elem_offset[CBF_LUMA] + !trafo_depth);
- }
-
--static int hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx)
-+static int hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx_nz)
- {
-- return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + !!c_idx);
-+ return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + c_idx_nz);
- }
-
--static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx)
-+static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx_nz)
- {
-- return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + !!c_idx);
-+ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + c_idx_nz);
- }
-
--static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx)
-+static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx_nz)
- {
-- return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + !!c_idx);
-+ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + c_idx_nz);
- }
-
- int ff_hevc_log2_res_scale_abs(HEVCContext *s, int idx) {
-@@ -891,14 +1154,14 @@ int ff_hevc_res_scale_sign_flag(HEVCContext *s, int idx) {
- return GET_CABAC(elem_offset[RES_SCALE_SIGN_FLAG] + idx);
- }
-
--static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx,
-+static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx_nz,
- int log2_size, int *last_scx_prefix, int *last_scy_prefix)
- {
- int i = 0;
- int max = (log2_size << 1) - 1;
- int ctx_offset, ctx_shift;
-
-- if (!c_idx) {
-+ if (!c_idx_nz) {
- ctx_offset = 3 * (log2_size - 2) + ((log2_size - 1) >> 2);
- ctx_shift = (log2_size + 1) >> 2;
- } else {
-@@ -929,22 +1192,16 @@ static av_always_inline int last_significant_coeff_suffix_decode(HEVCContext *s,
- return value;
- }
-
--static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg)
-+static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx_nz, int ctx_cg)
- {
- int inc;
-
-- inc = FFMIN(ctx_cg, 1) + (c_idx>0 ? 2 : 0);
-+ inc = (ctx_cg != 0) + (c_idx_nz << 1);
-
- return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_GROUP_FLAG] + inc);
- }
--static av_always_inline int significant_coeff_flag_decode(HEVCContext *s, int x_c, int y_c,
-- int offset, const uint8_t *ctx_idx_map)
--{
-- int inc = ctx_idx_map[(y_c << 2) + x_c] + offset;
-- return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + inc);
+-static uint32_t get_vc_address(AVBufferRef *bref) {
+- GPU_MEM_PTR_T *p = av_buffer_pool_opaque(bref);
+- return p->vc;
-}
-
--static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int c_idx, int offset)
-+static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int offset)
- {
- return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + offset);
- }
-@@ -966,65 +1223,305 @@ static av_always_inline int coeff_abs_level_greater2_flag_decode(HEVCContext *s,
- return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + inc);
- }
-
--static av_always_inline int coeff_abs_level_remaining_decode(HEVCContext *s, int rc_rice_param)
-+
-+#if !USE_BY22
-+#define coeff_abs_level_remaining_decode_bypass(s,r) coeff_abs_level_remaining_decode(s, r)
-+#endif
-+
-+
-+#ifndef coeff_abs_level_remaining_decode_bypass
-+static int coeff_abs_level_remaining_decode_bypass(HEVCContext * const s, const unsigned int rice_param)
-+{
-+ CABACContext * const c = &s->HEVClc->cc;
-+ uint32_t y;
-+ unsigned int prefix;
-+ unsigned int last_coeff_abs_level_remaining;
-+ unsigned int n;
-+
-+ y = get_cabac_by22_peek(c);
-+ prefix = hevc_clz32(~y);
-+ // y << prefix will always have top bit 0
-+
-+ if (prefix < 3) {
-+ const unsigned int suffix = (y << prefix) >> (31 - rice_param);
-+ last_coeff_abs_level_remaining = (prefix << rice_param) + suffix;
-+ n = prefix + 1 + rice_param;
-+ }
-+ else if (prefix * 2 + rice_param <= CABAC_BY22_PEEK_BITS + 2)
-+ {
-+ const uint32_t suffix = ((y << prefix) | 0x80000000) >> (34 - (prefix + rice_param));
-+
-+ last_coeff_abs_level_remaining = (2 << rice_param) + suffix;
-+ n = prefix * 2 + rice_param - 2;
-+ }
-+ else {
-+ unsigned int suffix;
-+
-+ get_cabac_by22_flush(c, prefix, y);
-+ y = get_cabac_by22_peek(c);
-+
-+ suffix = (y | 0x80000000) >> (34 - (prefix + rice_param));
-+ last_coeff_abs_level_remaining = (2 << rice_param) + suffix;
-+ n = prefix + rice_param - 2;
-+ }
-+
-+ get_cabac_by22_flush(c, n, y);
-+
-+ return last_coeff_abs_level_remaining;
-+}
-+#endif
-+
-+static int coeff_abs_level_remaining_decode(HEVCContext * const s, int rc_rice_param)
- {
-+ CABACContext * const c = &s->HEVClc->cc;
- int prefix = 0;
- int suffix = 0;
- int last_coeff_abs_level_remaining;
- int i;
-
-- while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc))
-+ while (prefix < CABAC_MAX_BIN && get_cabac_bypass(c))
- prefix++;
- if (prefix == CABAC_MAX_BIN) {
- av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix);
- return 0;
- }
-+
- if (prefix < 3) {
- for (i = 0; i < rc_rice_param; i++)
-- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc);
-+ suffix = (suffix << 1) | get_cabac_bypass(c);
- last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix;
- } else {
- int prefix_minus3 = prefix - 3;
- for (i = 0; i < prefix_minus3 + rc_rice_param; i++)
-- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc);
-+ suffix = (suffix << 1) | get_cabac_bypass(c);
- last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1)
- << rc_rice_param) + suffix;
- }
-+
- return last_coeff_abs_level_remaining;
- }
-
--static av_always_inline int coeff_sign_flag_decode(HEVCContext *s, uint8_t nb)
-+#if !USE_BY22
-+#define coeff_sign_flag_decode_bypass coeff_sign_flag_decode
-+static inline uint32_t coeff_sign_flag_decode(HEVCContext * const s, const unsigned int nb)
- {
-- int i;
-- int ret = 0;
-+ CABACContext * const c = &s->HEVClc->cc;
-+ unsigned int i;
-+ uint32_t ret = 0;
-
- for (i = 0; i < nb; i++)
-- ret = (ret << 1) | get_cabac_bypass(&s->HEVClc->cc);
-- return ret;
-+ ret = (ret << 1) | get_cabac_bypass(c);
-+
-+ return ret << (32 - nb);
- }
-+#endif
-+
-+#ifndef coeff_sign_flag_decode_bypass
-+static inline uint32_t coeff_sign_flag_decode_bypass(HEVCContext * const s, const unsigned int nb)
-+{
-+ CABACContext * const c = &s->HEVClc->cc;
-+ uint32_t y;
-+ y = get_cabac_by22_peek(c);
-+ get_cabac_by22_flush(c, nb, y);
-+ return y & ~(0xffffffffU >> nb);
-+}
-+#endif
-+
-+
-+#ifndef get_cabac_greater1_bits
-+static inline unsigned int get_cabac_greater1_bits(CABACContext * const c, const unsigned int n,
-+ uint8_t * const state0)
-+{
-+ unsigned int i;
-+ unsigned int rv = 0;
-+ for (i = 0; i != n; ++i) {
-+ const unsigned int idx = rv != 0 ? 0 : i < 3 ? i + 1 : 3;
-+ const unsigned int b = get_cabac(c, state0 + idx);
-+ rv = (rv << 1) | b;
-+ }
-+ return rv;
-+}
-+#endif
-+
-+
-+// N.B. levels returned are the values assuming coeff_abs_level_remaining
-+// is uncoded, so 1 must be added if it is coded. sum_abs also reflects
-+// this version of events.
-+static inline uint32_t get_greaterx_bits(HEVCContext * const s, const unsigned int n_end, int * const levels,
-+ int * const pprev_subset_coded, int * const psum,
-+ const unsigned int idx0_gt1, const unsigned int idx_gt2)
-+{
-+ CABACContext * const c = &s->HEVClc->cc;
-+ uint8_t * const state0 = s->HEVClc->cabac_state + idx0_gt1;
-+ uint8_t * const state_gt2 = s->HEVClc->cabac_state + idx_gt2;
-+ unsigned int rv;
-+ unsigned int i;
-+ const unsigned int n = FFMIN(n_end, 8);
-+
-+ // Really this is i != n but the simple unconditional loop is cheaper
-+ // and faster
-+ for (i = 0; i != 8; ++i)
-+ levels[i] = 1;
-+
-+ rv = get_cabac_greater1_bits(c, n, state0);
-+
-+ *pprev_subset_coded = 0;
-+ *psum = n;
-+
-+ rv <<= (32 - n);
-+ if (rv != 0)
-+ {
-+ *pprev_subset_coded = 1;
-+ *psum = n + 1;
-+ i = hevc_clz32(rv);
-+ levels[i] = 2;
-+ if (get_cabac(c, state_gt2) == 0)
-+ {
-+ // Unset first coded bit
-+ rv &= ~(0x80000000U >> i);
-+ }
-+ }
-+
-+ if (n_end > 8) {
-+ const unsigned int g8 = n_end - 8;
-+ rv |= ((1 << g8) - 1) << (24 - g8);
-+ for (i = 0; i != g8; ++i) {
-+ levels[i + 8] = 0;
-+ }
-+ }
-+
-+ return rv;
-+}
-+
-+// extended_precision_processing_flag must be false given we are
-+// putting the result into a 16-bit array
-+// So trans_coeff_level must fit in 16 bits too (7.4.9.1 definition of coeff_abs_level_remaining)
-+// scale_m is uint8_t
-+//
-+// scale is [40 - 72] << [0..12] based on qp- worst case is (45 << 12)
-+// or it can be 2 (if we have transquant_bypass)
-+// shift is set to one less than we really want but would normally be
-+// s->ps.sps->bit_depth (max 16, min 8) + log2_trafo_size (max 5, min 2?) - 5 = max 16 min 5?
-+// however the scale shift is substracted from shift to a min 0 so scale_m worst = 45 << 6
-+// This can still theoretically lead to overflow but the coding would have to be very odd (& inefficient)
-+// to achieve it
-+
-+#ifndef trans_scale_sat
-+static inline int trans_scale_sat(const int level, const unsigned int scale, const unsigned int scale_m, const unsigned int shift)
-+{
-+ return av_clip_int16((((level * (int)(scale * scale_m)) >> shift) + 1) >> 1);
-+}
-+#endif
-+
-+
-+#ifndef update_rice
-+static inline void update_rice(uint8_t * const stat_coeff,
-+ const unsigned int last_coeff_abs_level_remaining,
-+ const unsigned int c_rice_param)
-+{
-+ const unsigned int x = (last_coeff_abs_level_remaining << 1) >> c_rice_param;
-+ if (x >= 6)
-+ (*stat_coeff)++;
-+ else if (x == 0 && *stat_coeff > 0)
-+ (*stat_coeff)--;
-+}
-+#endif
-+
-+
-+// n must be > 0 on entry
-+#ifndef get_cabac_sig_coeff_flag_idxs
-+static inline uint8_t * get_cabac_sig_coeff_flag_idxs(CABACContext * const c, uint8_t * const state0,
-+ unsigned int n,
-+ const uint8_t const * ctx_map,
-+ uint8_t * p)
-+{
-+ do {
-+ if (get_cabac(c, state0 + ctx_map[n]))
-+ *p++ = n;
-+ } while (--n != 0);
-+ return p;
-+}
-+#endif
-+
-+
-+static int get_sig_coeff_flag_idxs(CABACContext * const c, uint8_t * const state0,
-+ unsigned int n,
-+ const uint8_t const * ctx_map,
-+ uint8_t * const flag_idx)
-+{
-+ int rv;
-+
-+ rv = get_cabac_sig_coeff_flag_idxs(c, state0, n, ctx_map, flag_idx) - flag_idx;
-+
-+ return rv;
-+}
-+
-+#define H4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\
-+ x0, x1, x2, x3,\
-+ x4, x5, x6, x7,\
-+ x8, x9, x10, x11,\
-+ x12, x13, x14, x15}
-+
-+#define V4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\
-+ x0, x4, x8, x12,\
-+ x1, x5, x9, x13,\
-+ x2, x6, x10, x14,\
-+ x3, x7, x11, x15}
-+
-+#define D4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\
-+ x0, x4, x1, x8,\
-+ x5, x2, x12, x9,\
-+ x6, x3, x13, x10,\
-+ x7, x14, x11, x15}
-+
-+
-+static inline int next_subset(HEVCContext * const s, int i, const int c_idx_nz,
-+ uint8_t * const significant_coeff_group_flag,
-+ const uint8_t * const scan_x_cg, const uint8_t * const scan_y_cg,
-+ int * const pPrev_sig)
-+{
-+ while (--i >= 0) {
-+ unsigned int x_cg = scan_x_cg[i];
-+ unsigned int y_cg = scan_y_cg[i];
-+
-+ // For the flag decode we only care about Z/NZ but
-+ // we use the full Right + Down * 2 when calculating
-+ // significant coeff flags so we obtain it here
-+ //.
-+ // The group flag array is one longer than it needs to
-+ // be so we don't need to check for y_cg limits
-+ unsigned int prev_sig = ((significant_coeff_group_flag[y_cg] >> (x_cg + 1)) & 1) |
-+ (((significant_coeff_group_flag[y_cg + 1] >> x_cg) & 1) << 1);
-+
-+ if (i == 0 ||
-+ significant_coeff_group_flag_decode(s, c_idx_nz, prev_sig))
-+ {
-+ significant_coeff_group_flag[y_cg] |= (1 << x_cg);
-+ *pPrev_sig = prev_sig;
-+ break;
-+ }
-+ }
-+
-+ return i;
-+}
-+
-
- void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- int log2_trafo_size, enum ScanType scan_idx,
- int c_idx)
- {
--#define GET_COORD(offset, n) \
-- do { \
-- x_c = (x_cg << 2) + scan_x_off[n]; \
-- y_c = (y_cg << 2) + scan_y_off[n]; \
-- } while (0)
-- HEVCLocalContext *lc = s->HEVClc;
-- int transform_skip_flag = 0;
-+ HEVCLocalContext * const lc = s->HEVClc;
-+ int trans_skip_or_bypass = lc->cu.cu_transquant_bypass_flag;
-
- int last_significant_coeff_x, last_significant_coeff_y;
-- int last_scan_pos;
-- int n_end;
- int num_coeff = 0;
-- int greater1_ctx = 1;
-+ int prev_subset_coded = 0;
-
- int num_last_subset;
- int x_cg_last_sig, y_cg_last_sig;
-
-- const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off;
-+ const uint8_t *scan_x_cg, *scan_y_cg;
-+ const xy_off_t * scan_xy_off;
-
- ptrdiff_t stride = s->frame->linesize[c_idx];
- int hshift = s->ps.sps->hshift[c_idx];
-@@ -1032,21 +1529,28 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride +
- ((x0 >> hshift) << s->ps.sps->pixel_shift)];
- #ifdef RPI
-- int use_vpu = s->enable_rpi && !lc->cu.cu_transquant_bypass_flag && !transform_skip_flag && !lc->tu.cross_pf && log2_trafo_size>=4;
-+ //***** transform_skip_flag decoded later!
-+ int use_vpu = s->enable_rpi && !lc->cu.cu_transquant_bypass_flag /* && !transform_skip_flag*/ && !lc->tu.cross_pf && log2_trafo_size>=4;
#endif
- int16_t *coeffs = (int16_t*)(c_idx ? lc->edge_emu_buffer2 : lc->edge_emu_buffer);
-- uint8_t significant_coeff_group_flag[8][8] = {{0}};
-+ uint8_t significant_coeff_group_flag[9] = {0}; // Allow 1 final byte that is always zero
- int explicit_rdpcm_flag = 0;
- int explicit_rdpcm_dir_flag;
- int trafo_size = 1 << log2_trafo_size;
- int i;
-- int qp,shift,add,scale,scale_m;
-- const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 };
-+ int qp,shift,scale;
-+ static const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 };
- const uint8_t *scale_matrix = NULL;
- uint8_t dc_scale;
- int pred_mode_intra = (c_idx == 0) ? lc->tu.intra_pred_mode :
- lc->tu.intra_pred_mode_c;
-+
-+ int prev_sig = 0;
-+ const int c_idx_nz = (c_idx != 0);
-+
-+ int may_hide_sign;
-+
+
+@@ -2186,9 +2182,9 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ int bw = nPbW-start_x;
+ int bh = nPbH-start_y;
+ y++[-RPI_LUMA_COMMAND_WORDS] = ((y1 - 3 + start_y) << 16) + ( (x1 - 3 + start_x) & 0xffff);
+- y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[0]);
++ y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address_y(ref0->frame);
+ y++[-RPI_LUMA_COMMAND_WORDS] = ((y1 - 3 + start_y) << 16) + ( (x1 - 3 + 8 + start_x) & 0xffff);
+- y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[0]);
++ y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address_y(ref0->frame);
+ *y++ = ( (bw<16 ? bw : 16) << 16 ) + (bh<16 ? bh : 16);
+ *y++ = my2_mx2_my_mx;
+ if (weight_flag) {
+@@ -2196,7 +2192,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ } else {
+ *y++ = 1; // Weight of 1 and offset of 0
+ }
+- *y++ = (get_vc_address(s->frame->buf[0]) + x0 + start_x + (start_y + y0) * s->frame->linesize[0]);
++ *y++ = (get_vc_address_y(s->frame) + x0 + start_x + (start_y + y0) * s->frame->linesize[0]);
+ y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter;
+ }
+ }
+@@ -2235,8 +2231,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ u++[-RPI_CHROMA_COMMAND_WORDS] = s->mc_filter_uv;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = x1_c - 1 + start_x;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = y1_c - 1 + start_y;
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[1]);
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[2]);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_u(ref0->frame);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_v(ref0->frame);
+ *u++ = ( (bwframe->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
+- *u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
++ *u++ = (get_vc_address_u(s->frame) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
++ *u++ = (get_vc_address_v(s->frame) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
+ }
+ }
+ s->curr_u_mvs = u;
+@@ -2286,9 +2282,9 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ int bw = nPbW-start_x;
+ int bh = nPbH-start_y;
+ y++[-RPI_LUMA_COMMAND_WORDS] = ((y1 - 3 + start_y) << 16) + ( (x1 - 3 + start_x) & 0xffff);
+- y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[0]);
++ y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address_y(ref1->frame);
+ y++[-RPI_LUMA_COMMAND_WORDS] = ((y1 - 3 + start_y) << 16) + ( (x1 - 3 + 8 + start_x) & 0xffff);
+- y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[0]);
++ y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address_y(ref1->frame);
+ *y++ = ( (bw<16 ? bw : 16) << 16 ) + (bh<16 ? bh : 16);
+ *y++ = my2_mx2_my_mx;
+ if (weight_flag) {
+@@ -2296,7 +2292,7 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ } else {
+ *y++ = 1; // Weight of 1 and offset of 0
+ }
+- *y++ = (get_vc_address(s->frame->buf[0]) + x0 + start_x + (start_y + y0) * s->frame->linesize[0]);
++ *y++ = (get_vc_address_y(s->frame) + x0 + start_x + (start_y + y0) * s->frame->linesize[0]);
+ y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter;
+ }
+ }
+@@ -2336,8 +2332,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ u++[-RPI_CHROMA_COMMAND_WORDS] = s->mc_filter_uv;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = x1_c - 1 + start_x;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = y1_c - 1 + start_y;
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[1]);
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[2]);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_u(ref1->frame);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_v(ref1->frame);
+ *u++ = ( (bwsh.chroma_weight_l0[current_mv.ref_idx[0]][0], s->sh.chroma_offset_l0[current_mv.ref_idx[0]][0]
+ *u++ = rpi_filter_coefs[_mx][0];
+@@ -2349,8 +2345,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ *u++ = 1; // Weight of 1 and offset of 0
+ *u++ = 1;
+ }
+- *u++ = (get_vc_address(s->frame->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
+- *u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
++ *u++ = (get_vc_address_u(s->frame) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
++ *u++ = (get_vc_address_v(s->frame) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
+ }
+ }
+ s->curr_u_mvs = u;
+@@ -2392,13 +2388,13 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ int bw = nPbW-start_x;
+ int bh = nPbH-start_y;
+ y++[-RPI_LUMA_COMMAND_WORDS] = ((y1 - 3 + start_y) << 16) + ( (x1 - 3 + start_x) & 0xffff);
+- y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[0]);
++ y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address_y(ref0->frame);
+ y++[-RPI_LUMA_COMMAND_WORDS] = ((y2 - 3 + start_y) << 16) + ( (x2 - 3 + start_x) & 0xffff); // Second fetch is for ref1
+- y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[0]);
++ y++[-RPI_LUMA_COMMAND_WORDS] = get_vc_address_y(ref1->frame);
+ *y++ = ( (bw<8 ? bw : 8) << 16 ) + (bh<16 ? bh : 16);
+ *y++ = my2_mx2_my_mx;
+ *y++ = 1; // B frame weighted prediction not supported
+- *y++ = (get_vc_address(s->frame->buf[0]) + x0 + start_x + (start_y + y0) * s->frame->linesize[0]);
++ *y++ = (get_vc_address_y(s->frame) + x0 + start_x + (start_y + y0) * s->frame->linesize[0]);
+ y++[-RPI_LUMA_COMMAND_WORDS] = s->mc_filter_b;
+ }
+ }
+@@ -2442,8 +2438,8 @@ static void hls_prediction_unit(HEVCContext *s, int x0, int y0,
+ u++[-RPI_CHROMA_COMMAND_WORDS] = s->mc_filter_uv_b0;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = x1_c - 1 + start_x;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = y1_c - 1 + start_y;
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[1]);
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref0->frame->buf[2]);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_u(ref0->frame);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_v(ref0->frame);
+ *u++ = ( (bwmc_filter_uv_b;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = x2_c - 1 + start_x;
+ u++[-RPI_CHROMA_COMMAND_WORDS] = y2_c - 1 + start_y;
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[1]);
+- u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address(ref1->frame->buf[2]);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_u(ref1->frame);
++ u++[-RPI_CHROMA_COMMAND_WORDS] = get_vc_address_v(ref1->frame);
+ *u++ = ( (bwframe->buf[1]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
+- *u++ = (get_vc_address(s->frame->buf[2]) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
++ *u++ = (get_vc_address_u(s->frame) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[1]);
++ *u++ = (get_vc_address_v(s->frame) + x0_c + start_x + (start_y + y0_c) * s->frame->linesize[2]);
+ }
+ }
+ s->curr_u_mvs = u;
+@@ -3259,12 +3255,13 @@ static int32_t filter8_luma(uint8_t *data, int x0, int y0, int pitch, int my_mx,
+ return vsum;
+ }
+
+-static uint8_t *test_frame(HEVCContext *s,uint32_t p, AVFrame *frame, int cIdx)
++static uint8_t *test_frame(HEVCContext *s,uint32_t p, AVFrame *frame, const int cIdx)
+ {
+ //int pic_width = s->ps.sps->width >> s->ps.sps->hshift[cIdx];
+ int pic_height = s->ps.sps->height >> s->ps.sps->vshift[cIdx];
+ int pitch = frame->linesize[cIdx];
+- uint32_t base = get_vc_address(frame->buf[cIdx]);
++ uint32_t base = c_idx == 0 ? get_vc_address_y(frame);
++ c_idx == 1 ? get_vc_address_u(frame) : get_vc_address_v(frame);
+ if (p>=base && pdata[cIdx] + (p-base);
+ }
+@@ -3551,6 +3548,7 @@ static void rpi_launch_vpu_qpu(HEVCContext *s)
#ifdef RPI
- if (s->enable_rpi) {
- int n = trafo_size * trafo_size;
-@@ -1078,7 +1582,7 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- // Derive QP for dequant
- if (!lc->cu.cu_transquant_bypass_flag) {
-- static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 };
-+ static const uint8_t qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 };
- static const uint8_t rem6[51 + 4 * 6 + 1] = {
- 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2,
- 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
-@@ -1094,9 +1598,19 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- };
- int qp_y = lc->qp_y;
+ #ifndef RPI_FAST_CACHEFLUSH
++#error RPI_FAST_CACHEFLUSH is broken
+ static void flush_buffer(AVBufferRef *bref) {
+ GPU_MEM_PTR_T *p = av_buffer_pool_opaque(bref);
+ gpu_cache_flush(p);
+@@ -3561,7 +3559,7 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
+ {
+ #ifdef RPI_FAST_CACHEFLUSH
+ struct vcsm_user_clean_invalid_s iocache = {};
+- GPU_MEM_PTR_T *p = av_buffer_pool_opaque(frame->buf[1]);
++ GPU_MEM_PTR_T p = get_gpu_mem_ptr_u(s->frame);
+ int n = s->ps.sps->height;
+ int curr_y = 0;
+ int curr_uv = 0;
+@@ -3569,21 +3567,21 @@ static void flush_frame(HEVCContext *s,AVFrame *frame)
+ int sz,base;
+ sz = s->frame->linesize[1] * (n_uv-curr_uv);
+ base = s->frame->linesize[1] * curr_uv;
+- iocache.s[0].handle = p->vcsm_handle;
++ iocache.s[0].handle = p.vcsm_handle;
+ iocache.s[0].cmd = 3; // clean+invalidate
+- iocache.s[0].addr = (int)(p->arm) + base;
++ iocache.s[0].addr = (int)(p.arm) + base;
+ iocache.s[0].size = sz;
+- p = av_buffer_pool_opaque(frame->buf[2]);
+- iocache.s[1].handle = p->vcsm_handle;
++ p = get_gpu_mem_ptr_v(s->frame);
++ iocache.s[1].handle = p.vcsm_handle;
+ iocache.s[1].cmd = 3; // clean+invalidate
+- iocache.s[1].addr = (int)(p->arm) + base;
++ iocache.s[1].addr = (int)(p.arm) + base;
+ iocache.s[1].size = sz;
+- p = av_buffer_pool_opaque(frame->buf[0]);
++ p = get_gpu_mem_ptr_y(s->frame);
+ sz = s->frame->linesize[0] * (n-curr_y);
+ base = s->frame->linesize[0] * curr_y;
+- iocache.s[2].handle = p->vcsm_handle;
++ iocache.s[2].handle = p.vcsm_handle;
+ iocache.s[2].cmd = 3; // clean+invalidate
+- iocache.s[2].addr = (int)(p->arm) + base;
++ iocache.s[2].addr = (int)(p.arm) + base;
+ iocache.s[2].size = sz;
+ vcsm_clean_invalid( &iocache );
+ #else
+@@ -3601,7 +3599,7 @@ static void flush_frame3(HEVCContext *s,AVFrame *frame,GPU_MEM_PTR_T *p0,GPU_MEM
+ int curr_y;
+ int curr_uv;
+ int n_uv;
+- GPU_MEM_PTR_T *p = av_buffer_pool_opaque(frame->buf[1]);
++ GPU_MEM_PTR_T p = get_gpu_mem_ptr_u(s->frame);
+ int sz,base;
+ int (*d)[2] = s->dblk_cmds[job];
+ int low=(*d)[1];
+@@ -3618,21 +3616,21 @@ static void flush_frame3(HEVCContext *s,AVFrame *frame,GPU_MEM_PTR_T *p0,GPU_MEM
-+ may_hide_sign = s->ps.pps->sign_data_hiding_flag;
+ sz = s->frame->linesize[1] * (n_uv-curr_uv);
+ base = s->frame->linesize[1] * curr_uv;
+- iocache.s[0].handle = p->vcsm_handle;
++ iocache.s[0].handle = p.vcsm_handle;
+ iocache.s[0].cmd = 3; // clean+invalidate
+- iocache.s[0].addr = (int)(p->arm) + base;
++ iocache.s[0].addr = (int)(p.arm) + base;
+ iocache.s[0].size = sz;
+- p = av_buffer_pool_opaque(frame->buf[2]);
+- iocache.s[1].handle = p->vcsm_handle;
++ p = get_gpu_mem_ptr_v(s->frame);
++ iocache.s[1].handle = p.vcsm_handle;
+ iocache.s[1].cmd = 3; // clean+invalidate
+- iocache.s[1].addr = (int)(p->arm) + base;
++ iocache.s[1].addr = (int)(p.arm) + base;
+ iocache.s[1].size = sz;
+- p = av_buffer_pool_opaque(frame->buf[0]);
++ p = get_gpu_mem_ptr_y(s->frame);
+ sz = s->frame->linesize[0] * (n-curr_y);
+ base = s->frame->linesize[0] * curr_y;
+- iocache.s[2].handle = p->vcsm_handle;
++ iocache.s[2].handle = p.vcsm_handle;
+ iocache.s[2].cmd = 3; // clean+invalidate
+- iocache.s[2].addr = (int)(p->arm) + base;
++ iocache.s[2].addr = (int)(p.arm) + base;
+ iocache.s[2].size = sz;
+
+ iocache.s[3].handle = p0->vcsm_handle;
+diff --git a/libavcodec/hevc_filter.c b/libavcodec/hevc_filter.c
+index 826a82f..c4fa305 100644
+--- a/libavcodec/hevc_filter.c
++++ b/libavcodec/hevc_filter.c
+@@ -879,17 +879,25 @@ void ff_hevc_deblocking_boundary_strengths(HEVCContext *s, int x0, int y0,
+ #undef CR
+
+ #ifdef RPI_INTER_QPU
+-static void flush_buffer(AVBufferRef *bref) {
+- GPU_MEM_PTR_T *p = av_buffer_pool_opaque(bref);
+- gpu_cache_flush(p);
++static void flush_buffer_y(const AVFrame * const frame) {
++ GPU_MEM_PTR_T p = get_gpu_mem_ptr_y(frame);
++ gpu_cache_flush(&p);
+ }
+
+-// Return Physical address for this image
+-static uint32_t get_vc_address(AVBufferRef *bref) {
+- GPU_MEM_PTR_T *p = av_buffer_pool_opaque(bref);
+- return p->vc;
++static void flush_buffer_u(const AVFrame * const frame) {
++ GPU_MEM_PTR_T p = get_gpu_mem_ptr_u(frame);
++ gpu_cache_flush(&p);
+ }
+
++static void flush_buffer_v(const AVFrame * const frame) {
++ GPU_MEM_PTR_T p = get_gpu_mem_ptr_v(frame);
++ gpu_cache_flush(&p);
++}
+
- if (s->ps.pps->transform_skip_enabled_flag &&
- log2_trafo_size <= s->ps.pps->log2_max_transform_skip_block_size) {
-- transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx);
-+ int transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx_nz);
-+ if (transform_skip_flag) {
-+ trans_skip_or_bypass = 1;
-+ if (lc->cu.pred_mode == MODE_INTRA &&
-+ s->ps.sps->implicit_rdpcm_enabled_flag &&
-+ (pred_mode_intra == 10 || pred_mode_intra == 26)) {
-+ may_hide_sign = 0;
-+ }
-+ }
++
++#ifdef RPI_DEBLOCK_VPU
++#error Not fixed yet
++
+ // ff_hevc_flush_buffer_lines
+ // flushes and invalidates all pixel rows in [start,end-1]
+ static void ff_hevc_flush_buffer_lines(HEVCContext *s, int start, int end, int flush_luma, int flush_chroma)
+@@ -901,44 +909,44 @@ static void ff_hevc_flush_buffer_lines(HEVCContext *s, int start, int end, int f
+ int curr_uv = curr_y >> s->ps.sps->vshift[1];
+ int n_uv = n >> s->ps.sps->vshift[1];
+ int sz,base;
+- GPU_MEM_PTR_T *p;
++ GPU_MEM_PTR_T p;
+ if (curr_uv < 0) curr_uv = 0;
+ if (n_uv<=curr_uv) { return; }
+ sz = s->frame->linesize[1] * (n_uv-curr_uv);
+ base = s->frame->linesize[1] * curr_uv;
+ if (flush_chroma) {
+- p = av_buffer_pool_opaque(s->frame->buf[1]);
+- iocache.s[0].handle = p->vcsm_handle;
++ p = get_gpu_mem_ptr_u(s->frame);
++ iocache.s[0].handle = p.vcsm_handle;
+ iocache.s[0].cmd = 3; // clean+invalidate
+- iocache.s[0].addr = (int)p->arm + base;
++ iocache.s[0].addr = (int)p.arm + base;
+ iocache.s[0].size = sz;
+- p = av_buffer_pool_opaque(s->frame->buf[2]);
+- iocache.s[1].handle = p->vcsm_handle;
++ p = get_gpu_mem_ptr_v(s->frame);
++ iocache.s[1].handle = p.vcsm_handle;
+ iocache.s[1].cmd = 3; // clean+invalidate
+- iocache.s[1].addr = (int)p->arm + base;
++ iocache.s[1].addr = (int)p.arm + base;
+ iocache.s[1].size = sz;
}
-
- if (c_idx == 0) {
-@@ -1129,39 +1643,73 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- qp += s->ps.sps->qp_bd_offset;
+ if (flush_luma) {
+- p = av_buffer_pool_opaque(s->frame->buf[0]);
++ p = get_gpu_mem_ptr_y(s->frame);
+ sz = s->frame->linesize[0] * (n-curr_y);
+ base = s->frame->linesize[0] * curr_y;
+- iocache.s[2].handle = p->vcsm_handle;
++ iocache.s[2].handle = p.vcsm_handle;
+ iocache.s[2].cmd = 3; // clean+invalidate
+- iocache.s[2].addr = (int)p->arm + base;
++ iocache.s[2].addr = (int)p.arm + base;
+ iocache.s[2].size = sz;
}
+ vcsm_clean_invalid( &iocache );
+ #else
+ if (flush_chroma) {
+- flush_buffer(s->frame->buf[1]);
+- flush_buffer(s->frame->buf[2]);
++ flush_buffer_u(s->frame);
++ flush_buffer_v(s->frame);
+ }
+ if (flush_luma) {
+- flush_buffer(s->frame->buf[0]);
++ flush_buffer_y(s->frame);
+ }
+ #endif
+ }
+-
++#endif
-- shift = s->ps.sps->bit_depth + log2_trafo_size - 5;
-- add = 1 << (shift-1);
-- scale = level_scale[rem6[qp]] << (div6[qp]);
-- scale_m = 16; // default when no custom scaling lists.
-- dc_scale = 16;
-+ // Shift is set to one less than will actually occur as the scale
-+ // and saturate step adds 1 and then shifts right again
-+ shift = s->ps.sps->bit_depth + log2_trafo_size - 6;
-+ scale = level_scale[rem6[qp]];
-+ if (div6[qp] >= shift) {
-+ scale <<= (div6[qp] - shift);
-+ shift = 0;
-+ } else {
-+ shift -= div6[qp];
+ void ff_hevc_flush_buffer(HEVCContext *s, ThreadFrame *f, int n)
+ {
+@@ -950,37 +958,37 @@ void ff_hevc_flush_buffer(HEVCContext *s, ThreadFrame *f, int n)
+ int curr_uv = curr_y >> s->ps.sps->vshift[1];
+ int n_uv = n >> s->ps.sps->vshift[1];
+ int sz,base;
+- GPU_MEM_PTR_T *p;
++ GPU_MEM_PTR_T p;
+ if (curr_uv < 0) curr_uv = 0;
+ if (n_uv<=curr_uv) { return; }
+ sz = s->frame->linesize[1] * (n_uv-curr_uv);
+ base = s->frame->linesize[1] * curr_uv;
+- p = av_buffer_pool_opaque(s->frame->buf[1]);
+- iocache.s[0].handle = p->vcsm_handle;
++ p = get_gpu_mem_ptr_u(s->frame);
++ iocache.s[0].handle = p.vcsm_handle;
+ iocache.s[0].cmd = 3; // clean+invalidate
+- iocache.s[0].addr = (int)p->arm + base;
++ iocache.s[0].addr = (int)p.arm + base;
+ iocache.s[0].size = sz;
+- p = av_buffer_pool_opaque(s->frame->buf[2]);
+- iocache.s[1].handle = p->vcsm_handle;
++ p = get_gpu_mem_ptr_v(s->frame);
++ iocache.s[1].handle = p.vcsm_handle;
+ iocache.s[1].cmd = 3; // clean+invalidate
+- iocache.s[1].addr = (int)p->arm + base;
++ iocache.s[1].addr = (int)p.arm + base;
+ iocache.s[1].size = sz;
+
+ #ifdef RPI_LUMA_QPU
+- p = av_buffer_pool_opaque(s->frame->buf[0]);
++ p = get_gpu_mem_ptr_y(s->frame);
+ sz = s->frame->linesize[0] * (n-curr_y);
+ base = s->frame->linesize[0] * curr_y;
+- iocache.s[2].handle = p->vcsm_handle;
++ iocache.s[2].handle = p.vcsm_handle;
+ iocache.s[2].cmd = 3; // clean+invalidate
+- iocache.s[2].addr = (int)p->arm + base;
++ iocache.s[2].addr = (int)p.arm + base;
+ iocache.s[2].size = sz;
+ #endif
+ vcsm_clean_invalid( &iocache );
+ #else
+- flush_buffer(s->frame->buf[1]);
+- flush_buffer(s->frame->buf[2]);
++ flush_buffer_u(s->frame);
++ flush_buffer_v(s->frame);
+ #ifdef RPI_LUMA_QPU
+- flush_buffer(s->frame->buf[0]);
++ flush_buffer_y(s->frame);
+ #endif
+
+ #endif
+@@ -992,6 +1000,7 @@ void ff_hevc_flush_buffer(HEVCContext *s, ThreadFrame *f, int n)
+ #endif
+
+ #ifdef RPI_DEBLOCK_VPU
++#error XXX
+ /* rpi_deblock deblocks an entire row of ctbs using the VPU */
+ static void rpi_deblock(HEVCContext *s, int y, int ctb_size)
+ {
+@@ -1000,21 +1009,21 @@ static void rpi_deblock(HEVCContext *s, int y, int ctb_size)
+ // TODO flush buffer of beta/tc setup when it becomes cached
+
+ // Prepare three commands at once to avoid calling overhead
+- s->vpu_cmds_arm[0][0] = get_vc_address(s->frame->buf[0]) + s->frame->linesize[0] * y;
++ s->vpu_cmds_arm[0][0] = get_vc_address_y(s->frame) + s->frame->linesize[0] * y;
+ s->vpu_cmds_arm[0][1] = s->frame->linesize[0];
+ s->vpu_cmds_arm[0][2] = s->setup_width;
+ s->vpu_cmds_arm[0][3] = (int) ( s->y_setup_vc + s->setup_width * (y>>4) );
+ s->vpu_cmds_arm[0][4] = ctb_size>>4;
+ s->vpu_cmds_arm[0][5] = 2;
+
+- s->vpu_cmds_arm[1][0] = get_vc_address(s->frame->buf[1]) + s->frame->linesize[1] * (y>> s->ps.sps->vshift[1]);
++ s->vpu_cmds_arm[1][0] = get_vc_address_u(s->frame) + s->frame->linesize[1] * (y>> s->ps.sps->vshift[1]);
+ s->vpu_cmds_arm[1][1] = s->frame->linesize[1];
+ s->vpu_cmds_arm[1][2] = s->uv_setup_width;
+ s->vpu_cmds_arm[1][3] = (int) ( s->uv_setup_vc + s->uv_setup_width * ((y>>4)>> s->ps.sps->vshift[1]) );
+ s->vpu_cmds_arm[1][4] = (ctb_size>>4)>> s->ps.sps->vshift[1];
+ s->vpu_cmds_arm[1][5] = 3;
+
+- s->vpu_cmds_arm[2][0] = get_vc_address(s->frame->buf[2]) + s->frame->linesize[2] * (y>> s->ps.sps->vshift[2]);
++ s->vpu_cmds_arm[2][0] = get_vc_address_v(s->frame) + s->frame->linesize[2] * (y>> s->ps.sps->vshift[2]);
+ s->vpu_cmds_arm[2][1] = s->frame->linesize[2];
+ s->vpu_cmds_arm[2][2] = s->uv_setup_width;
+ s->vpu_cmds_arm[2][3] = (int) ( s->uv_setup_vc + s->uv_setup_width * ((y>>4)>> s->ps.sps->vshift[1]) );
+diff --git a/libavcodec/rpi_qpu.c b/libavcodec/rpi_qpu.c
+index ffd13ca..b0c9bc5 100644
+--- a/libavcodec/rpi_qpu.c
++++ b/libavcodec/rpi_qpu.c
+@@ -250,7 +250,7 @@ int gpu_get_mailbox(void)
+ }
+
+ // Call this to clean and invalidate a region of memory
+-void gpu_cache_flush(GPU_MEM_PTR_T *p)
++void gpu_cache_flush(const GPU_MEM_PTR_T * const p)
+ {
+ #ifdef RPI_FAST_CACHEFLUSH
+ struct vcsm_user_clean_invalid_s iocache = {};
+diff --git a/libavcodec/rpi_qpu.h b/libavcodec/rpi_qpu.h
+index 81c2bb1..b913f79 100644
+--- a/libavcodec/rpi_qpu.h
++++ b/libavcodec/rpi_qpu.h
+@@ -2,8 +2,11 @@
+ #define RPI_QPU_H
+
+ // Define RPI_FAST_CACHEFLUSH to use the VCSM cache flush code
++// *** N.B. Code has rotted & crashes if this is unset (before this set of changes)
+ #define RPI_FAST_CACHEFLUSH
+
++#define RPI_ONE_BUF 1
++
+ typedef struct gpu_mem_ptr_s {
+ unsigned char *arm; // Pointer to memory mapped on ARM side
+ int vc_handle; // Videocore handle of relocatable memory
+@@ -16,9 +19,113 @@ typedef struct gpu_mem_ptr_s {
+ extern int gpu_malloc_cached(int numbytes, GPU_MEM_PTR_T *p);
+ extern int gpu_malloc_uncached(int numbytes, GPU_MEM_PTR_T *p);
+ extern void gpu_free(GPU_MEM_PTR_T *p);
+-extern void gpu_cache_flush(GPU_MEM_PTR_T *p);
++extern void gpu_cache_flush(const GPU_MEM_PTR_T * const p);
+ extern void gpu_cache_flush3(GPU_MEM_PTR_T *p0,GPU_MEM_PTR_T *p1,GPU_MEM_PTR_T *p2);
+
++#include "libavutil/frame.h"
++#if !RPI_ONE_BUF
++static inline uint32_t get_vc_address_y(const AVFrame * const frame) {
++ GPU_MEM_PTR_T *p = av_buffer_pool_opaque(frame->buf[0]);
++ return p->vc;
++}
++
++static inline uint32_t get_vc_address_u(const AVFrame * const frame) {
++ GPU_MEM_PTR_T *p = av_buffer_pool_opaque(frame->buf[1]);
++ return p->vc;
++}
++
++static inline uint32_t get_vc_address_v(const AVFrame * const frame) {
++ GPU_MEM_PTR_T *p = av_buffer_pool_opaque(frame->buf[2]);
++ return p->vc;
++}
++
++static inline GPU_MEM_PTR_T get_gpu_mem_ptr_y(const AVFrame * const frame) {
++ return *(GPU_MEM_PTR_T *)av_buffer_pool_opaque(frame->buf[0]);
++}
++
++static inline GPU_MEM_PTR_T get_gpu_mem_ptr_u(const AVFrame * const frame) {
++ return *(GPU_MEM_PTR_T *)av_buffer_pool_opaque(frame->buf[1]);
++}
++
++static inline GPU_MEM_PTR_T get_gpu_mem_ptr_v(const AVFrame * const frame) {
++ return *(GPU_MEM_PTR_T *)av_buffer_pool_opaque(frame->buf[2]);
++}
++
++#else
++
++static inline int gpu_is_buf1(const AVFrame * const frame)
++{
++ return frame->buf[1] == NULL;
++}
++
++static inline GPU_MEM_PTR_T * gpu_buf1_gmem(const AVFrame * const frame)
++{
++ return av_buffer_get_opaque(frame->buf[0]);
++}
++
++static inline GPU_MEM_PTR_T * gpu_buf3_gmem(const AVFrame * const frame, const int n)
++{
++ return av_buffer_pool_opaque(frame->buf[n]);
++}
++
++
++static inline uint32_t get_vc_address_y(const AVFrame * const frame) {
++ return gpu_is_buf1(frame) ? gpu_buf1_gmem(frame)->vc : gpu_buf3_gmem(frame, 0)->vc;
++}
++
++static inline uint32_t get_vc_address_u(const AVFrame * const frame) {
++ return gpu_is_buf1(frame) ?
++ gpu_buf1_gmem(frame)->vc + frame->data[1] - frame->data[0] :
++ gpu_buf3_gmem(frame, 1)->vc;
++}
++
++static inline uint32_t get_vc_address_v(const AVFrame * const frame) {
++ return gpu_is_buf1(frame) ?
++ gpu_buf1_gmem(frame)->vc + frame->data[2] - frame->data[0] :
++ gpu_buf3_gmem(frame, 2)->vc;
++}
++
++
++static inline GPU_MEM_PTR_T get_gpu_mem_ptr_y(const AVFrame * const frame) {
++ if (gpu_is_buf1(frame))
++ {
++ GPU_MEM_PTR_T g = *gpu_buf1_gmem(frame);
++ g.numbytes = frame->data[1] - frame->data[0];
++ return g;
++ }
++ else
++ return *gpu_buf3_gmem(frame, 0);
++}
++
++static inline GPU_MEM_PTR_T get_gpu_mem_ptr_u(const AVFrame * const frame) {
++ if (gpu_is_buf1(frame))
++ {
++ GPU_MEM_PTR_T g = *gpu_buf1_gmem(frame);
++ g.arm += frame->data[1] - frame->data[0];
++ g.vc += frame->data[1] - frame->data[0];
++ g.numbytes = frame->data[2] - frame->data[1]; // chroma size
++ return g;
++ }
++ else
++ return *gpu_buf3_gmem(frame, 1);
++}
++
++static inline GPU_MEM_PTR_T get_gpu_mem_ptr_v(const AVFrame * const frame) {
++ if (gpu_is_buf1(frame))
++ {
++ GPU_MEM_PTR_T g = *gpu_buf1_gmem(frame);
++ g.arm += frame->data[2] - frame->data[0];
++ g.vc += frame->data[2] - frame->data[0];
++ g.numbytes = frame->data[2] - frame->data[1]; // chroma size
++ return g;
++ }
++ else
++ return *gpu_buf3_gmem(frame, 2);
++}
++
++#endif
++
++
+ // QPU specific functions
+ extern void qpu_run_shader8(int code, int unifs1, int unifs2, int unifs3, int unifs4, int unifs5, int unifs6, int unifs7, int unifs8);
+ extern void qpu_run_shader12(int code, int num, int code2, int num2, int unifs1, int unifs2, int unifs3, int unifs4, int unifs5, int unifs6, int unifs7, int unifs8, int unifs9, int unifs10, int unifs11, int unifs12);
+diff --git a/libavcodec/rpi_zc.c b/libavcodec/rpi_zc.c
+new file mode 100644
+index 0000000..9580165
+--- /dev/null
++++ b/libavcodec/rpi_zc.c
+@@ -0,0 +1,406 @@
++#include "config.h"
++#ifdef RPI
++#include "rpi_qpu.h"
++#include "rpi_zc.h"
++
++#include "libavutil/buffer_internal.h"
++
++struct ZcPoolEnt;
++
++typedef struct ZcPool
++{
++ int numbytes;
++ struct ZcPoolEnt * head;
++ pthread_mutex_t lock;
++} ZcPool;
++
++typedef struct ZcPoolEnt
++{
++ // It is important that we start with gmem as other bits of code will expect to see that
++ GPU_MEM_PTR_T gmem;
++ struct ZcPoolEnt * next;
++ struct ZcPool * pool;
++} ZcPoolEnt;
++
++static ZcPoolEnt * zc_pool_ent_alloc(ZcPool * const pool, const int size)
++{
++ ZcPoolEnt * const zp = av_malloc(sizeof(ZcPoolEnt));
++
++ if (zp == NULL) {
++ av_log(NULL, AV_LOG_ERROR, "av_malloc(ZcPoolEnt) failed\n");
++ goto fail0;
++ }
++
++ if (gpu_malloc_cached(size, &zp->gmem) != 0)
++ {
++ av_log(NULL, AV_LOG_ERROR, "av_gpu_malloc_cached(%d) failed\n", size);
++ goto fail1;
++ }
++
++ zp->next = NULL;
++ zp->pool = pool;
++ return zp;
++
++fail1:
++ av_free(zp);
++fail0:
++ return NULL;
++}
++
++static void zc_pool_ent_free(ZcPoolEnt * const zp)
++{
++ gpu_free(&zp->gmem);
++ av_free(zp);
++}
++
++static void zc_pool_flush(ZcPool * const pool)
++{
++ ZcPoolEnt * p = pool->head;
++ pool->head = NULL;
++ while (p != NULL)
++ {
++ ZcPoolEnt * const zp = p;
++ p = p->next;
++ zc_pool_ent_free(zp);
++ }
++}
++
++static ZcPoolEnt * zc_pool_alloc(ZcPool * const pool, const int numbytes)
++{
++ ZcPoolEnt * zp;
++ pthread_mutex_lock(&pool->lock);
++
++ if (numbytes != pool->numbytes)
++ {
++ zc_pool_flush(pool);
++ pool->numbytes = numbytes;
++ }
++
++ if (pool->head != NULL)
++ {
++ zp = pool->head;
++ pool->head = zp->next;
++ }
++ else
++ {
++ zp = zc_pool_ent_alloc(pool, numbytes);
++ }
++
++ pthread_mutex_unlock(&pool->lock);
++ return zp;
++}
++
++static void zc_pool_free(ZcPoolEnt * const zp)
++{
++ ZcPool * const pool = zp == NULL ? NULL : zp->pool;
++ if (zp != NULL)
++ {
++ pthread_mutex_lock(&pool->lock);
++ if (pool->numbytes == zp->gmem.numbytes)
++ {
++ zp->next = pool->head;
++ pool->head = zp;
++ pthread_mutex_unlock(&pool->lock);
+ }
-
-- if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
-+ if (s->ps.sps->scaling_list_enable_flag && !(trans_skip_or_bypass && log2_trafo_size > 2)) {
- const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ?
-- &s->ps.pps->scaling_list : &s->ps.sps->scaling_list;
-+ &s->ps.pps->scaling_list : &s->ps.sps->scaling_list;
- int matrix_id = lc->cu.pred_mode != MODE_INTRA;
-
- matrix_id = 3 * matrix_id + c_idx;
-
- scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id];
-+ dc_scale = scale_matrix[0];
- if (log2_trafo_size >= 4)
- dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id];
- }
+ else
+ {
-+ static const uint8_t sixteen_scale[64] = {
-+ 16, 16, 16, 16, 16, 16, 16, 16,
-+ 16, 16, 16, 16, 16, 16, 16, 16,
-+ 16, 16, 16, 16, 16, 16, 16, 16,
-+ 16, 16, 16, 16, 16, 16, 16, 16,
-+ 16, 16, 16, 16, 16, 16, 16, 16,
-+ 16, 16, 16, 16, 16, 16, 16, 16,
-+ 16, 16, 16, 16, 16, 16, 16, 16,
-+ 16, 16, 16, 16, 16, 16, 16, 16
-+ };
-+ scale_matrix = sixteen_scale;
-+ dc_scale = 16;
++ pthread_mutex_unlock(&pool->lock);
++ zc_pool_ent_free(zp);
+ }
- } else {
-+ static const uint8_t unit_scale[64] = {
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ 1, 1, 1, 1, 1, 1, 1, 1,
-+ };
-+ scale_matrix = unit_scale;
- shift = 0;
-- add = 0;
-- scale = 0;
-- dc_scale = 0;
-+ scale = 2; // We will shift right to kill this
-+ dc_scale = 1;
++ }
++}
+
-+ may_hide_sign = 0;
- }
-
- if (lc->cu.pred_mode == MODE_INTER && s->ps.sps->explicit_rdpcm_enabled_flag &&
-- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
-- explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx);
-+ trans_skip_or_bypass) {
-+ explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx_nz);
- if (explicit_rdpcm_flag) {
-- explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx);
-+ may_hide_sign = 0;
-+ explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx_nz);
- }
- }
-
-- last_significant_coeff_xy_prefix_decode(s, c_idx, log2_trafo_size,
-+ last_significant_coeff_xy_prefix_decode(s, c_idx_nz, log2_trafo_size,
- &last_significant_coeff_x, &last_significant_coeff_y);
-
- if (last_significant_coeff_x > 3) {
-@@ -1189,119 +1737,113 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- int last_x_c = last_significant_coeff_x & 3;
- int last_y_c = last_significant_coeff_y & 3;
-
-- scan_x_off = ff_hevc_diag_scan4x4_x;
-- scan_y_off = ff_hevc_diag_scan4x4_y;
- num_coeff = diag_scan4x4_inv[last_y_c][last_x_c];
-- if (trafo_size == 4) {
++static void
++zc_pool_init(ZcPool * const pool)
++{
++ pool->numbytes = -1;
++ pool->head = NULL;
++ pthread_mutex_init(&pool->lock, NULL);
++}
+
-+ switch (log2_trafo_size) {
-+ case 2:
- scan_x_cg = scan_1x1;
- scan_y_cg = scan_1x1;
-- } else if (trafo_size == 8) {
-+ break;
-+ case 3:
- num_coeff += diag_scan2x2_inv[y_cg_last_sig][x_cg_last_sig] << 4;
- scan_x_cg = diag_scan2x2_x;
- scan_y_cg = diag_scan2x2_y;
-- } else if (trafo_size == 16) {
-+ break;
-+ case 4:
- num_coeff += diag_scan4x4_inv[y_cg_last_sig][x_cg_last_sig] << 4;
- scan_x_cg = ff_hevc_diag_scan4x4_x;
- scan_y_cg = ff_hevc_diag_scan4x4_y;
-- } else { // trafo_size == 32
-+ break;
-+ case 5:
-+ default:
- num_coeff += diag_scan8x8_inv[y_cg_last_sig][x_cg_last_sig] << 4;
- scan_x_cg = ff_hevc_diag_scan8x8_x;
- scan_y_cg = ff_hevc_diag_scan8x8_y;
-+ break;
- }
- break;
- }
- case SCAN_HORIZ:
- scan_x_cg = horiz_scan2x2_x;
- scan_y_cg = horiz_scan2x2_y;
-- scan_x_off = horiz_scan4x4_x;
-- scan_y_off = horiz_scan4x4_y;
- num_coeff = horiz_scan8x8_inv[last_significant_coeff_y][last_significant_coeff_x];
- break;
- default: //SCAN_VERT
- scan_x_cg = horiz_scan2x2_y;
- scan_y_cg = horiz_scan2x2_x;
-- scan_x_off = horiz_scan4x4_y;
-- scan_y_off = horiz_scan4x4_x;
- num_coeff = horiz_scan8x8_inv[last_significant_coeff_x][last_significant_coeff_y];
- break;
- }
- num_coeff++;
- num_last_subset = (num_coeff - 1) >> 4;
-
-- for (i = num_last_subset; i >= 0; i--) {
-- int n, m;
-- int x_cg, y_cg, x_c, y_c, pos;
-- int implicit_non_zero_coeff = 0;
-- int64_t trans_coeff_level;
-- int prev_sig = 0;
-- int offset = i << 4;
-- int rice_init = 0;
--
-- uint8_t significant_coeff_flag_idx[16];
-- uint8_t nb_significant_coeff_flag = 0;
-+ significant_coeff_group_flag[y_cg_last_sig] = 1 << x_cg_last_sig; // 1st subset always significant
-
-- x_cg = scan_x_cg[i];
-- y_cg = scan_y_cg[i];
-+ scan_xy_off = off_xys[scan_idx][log2_trafo_size - 2];
-
-- if ((i < num_last_subset) && (i > 0)) {
-- int ctx_cg = 0;
-- if (x_cg < (1 << (log2_trafo_size - 2)) - 1)
-- ctx_cg += significant_coeff_group_flag[x_cg + 1][y_cg];
-- if (y_cg < (1 << (log2_trafo_size - 2)) - 1)
-- ctx_cg += significant_coeff_group_flag[x_cg][y_cg + 1];
--
-- significant_coeff_group_flag[x_cg][y_cg] =
-- significant_coeff_group_flag_decode(s, c_idx, ctx_cg);
-- implicit_non_zero_coeff = 1;
-- } else {
-- significant_coeff_group_flag[x_cg][y_cg] =
-- ((x_cg == x_cg_last_sig && y_cg == y_cg_last_sig) ||
-- (x_cg == 0 && y_cg == 0));
-- }
-+ i = num_last_subset;
-+ do {
-+ int implicit_non_zero_coeff = 0;
-+ int n_end;
-
-- last_scan_pos = num_coeff - offset - 1;
-+ uint8_t significant_coeff_flag_idx[16];
-+ unsigned int nb_significant_coeff_flag = 0;
-
- if (i == num_last_subset) {
-+ // First time through
-+ int last_scan_pos = num_coeff - (i << 4) - 1;
- n_end = last_scan_pos - 1;
- significant_coeff_flag_idx[0] = last_scan_pos;
- nb_significant_coeff_flag = 1;
- } else {
- n_end = 15;
-+ implicit_non_zero_coeff = (i != 0);
- }
-
-- if (x_cg < ((1 << log2_trafo_size) - 1) >> 2)
-- prev_sig = !!significant_coeff_group_flag[x_cg + 1][y_cg];
-- if (y_cg < ((1 << log2_trafo_size) - 1) >> 2)
-- prev_sig += (!!significant_coeff_group_flag[x_cg][y_cg + 1] << 1);
--
-- if (significant_coeff_group_flag[x_cg][y_cg] && n_end >= 0) {
-- static const uint8_t ctx_idx_map[] = {
-- 0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8, // log2_trafo_size == 2
-- 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 0
-- 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 1
-- 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, // prev_sig == 2
-- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // default
-+ if (n_end >= 0) {
-+ static const uint8_t ctx_idx_maps_ts2[3][16] = {
-+ D4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8), // log2_trafo_size == 2
-+ H4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8), // log2_trafo_size == 2
-+ V4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8) // log2_trafo_size == 2
-+ };
-+ static const uint8_t ctx_idx_maps[3][4][16] = {
-+ {
-+ D4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0
-+ D4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1
-+ D4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2
-+ D4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default
-+ },
-+ {
-+ H4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0
-+ H4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1
-+ H4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2
-+ H4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default
-+ },
-+ {
-+ V4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0
-+ V4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1
-+ V4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2
-+ V4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default
-+ }
- };
- const uint8_t *ctx_idx_map_p;
- int scf_offset = 0;
-- if (s->ps.sps->transform_skip_context_enabled_flag &&
-- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
-- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[4 * 16];
-- if (c_idx == 0) {
-- scf_offset = 40;
-- } else {
-- scf_offset = 14 + 27;
-- }
++static void
++zc_pool_destroy(ZcPool * const pool)
++{
++ pool->numbytes = -1;
++ zc_pool_flush(pool);
++ pthread_mutex_destroy(&pool->lock);
++}
+
-+ if (s->ps.sps->transform_skip_context_enabled_flag && trans_skip_or_bypass) {
-+ ctx_idx_map_p = ctx_idx_maps[0][3];
-+ scf_offset = 40 + c_idx_nz;
- } else {
-- if (c_idx != 0)
-+ if (c_idx_nz != 0)
- scf_offset = 27;
+
- if (log2_trafo_size == 2) {
-- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[0];
-+ ctx_idx_map_p = ctx_idx_maps_ts2[scan_idx];
- } else {
-- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[(prev_sig + 1) << 4];
-- if (c_idx == 0) {
-- if ((x_cg > 0 || y_cg > 0))
-+ ctx_idx_map_p = ctx_idx_maps[scan_idx][prev_sig];
-+ if (!c_idx_nz) {
-+ if (i != 0)
- scf_offset += 3;
++typedef struct AVZcEnv
++{
++ ZcPool pool;
++} ZcEnv;
+
- if (log2_trafo_size == 3) {
- scf_offset += (scan_idx == SCAN_DIAG) ? 9 : 15;
- } else {
-@@ -1315,34 +1857,30 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- }
- }
- }
-- for (n = n_end; n > 0; n--) {
-- x_c = scan_x_off[n];
-- y_c = scan_y_off[n];
-- if (significant_coeff_flag_decode(s, x_c, y_c, scf_offset, ctx_idx_map_p)) {
-- significant_coeff_flag_idx[nb_significant_coeff_flag] = n;
-- nb_significant_coeff_flag++;
++// Callback when buffer unrefed to zero
++static void rpi_free_display_buffer(void *opaque, uint8_t *data)
++{
++ ZcPoolEnt *const zp = opaque;
++// printf("%s: data=%p\n", __func__, data);
++ zc_pool_free(zp);
++}
+
-+ if (n_end > 0) {
-+ int cnt = get_sig_coeff_flag_idxs(&s->HEVClc->cc,
-+ s->HEVClc->cabac_state + elem_offset[SIGNIFICANT_COEFF_FLAG] + scf_offset,
-+ n_end, ctx_idx_map_p,
-+ significant_coeff_flag_idx + nb_significant_coeff_flag);
++static inline GPU_MEM_PTR_T * pic_gm_ptr(AVBufferRef * const buf)
++{
++ // Kludge where we check the free fn to check this is really
++ // one of our buffers - can't think of a better way
++ return buf == NULL || buf->buffer->free != rpi_free_display_buffer ? NULL :
++ av_buffer_get_opaque(buf);
++}
+
-+ nb_significant_coeff_flag += cnt;
-+ if (cnt != 0) {
- implicit_non_zero_coeff = 0;
- }
- }
++AVRpiZcFrameGeometry av_rpi_zc_frame_geometry(
++ const unsigned int video_width, const unsigned int video_height)
++{
++ AVRpiZcFrameGeometry geo;
++ geo.stride_y = (video_width + 32 + 31) & ~31;
++ geo.stride_c = geo.stride_y / 2;
++// geo.height_y = (video_height + 15) & ~15;
++ geo.height_y = (video_height + 32 + 31) & ~31;
++ geo.height_c = geo.height_y / 2;
++ return geo;
++}
+
- if (implicit_non_zero_coeff == 0) {
-- if (s->ps.sps->transform_skip_context_enabled_flag &&
-- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
-- if (c_idx == 0) {
-- scf_offset = 42;
-- } else {
-- scf_offset = 16 + 27;
-- }
-+ if (s->ps.sps->transform_skip_context_enabled_flag && trans_skip_or_bypass) {
-+ scf_offset = 42 + c_idx_nz;
- } else {
- if (i == 0) {
-- if (c_idx == 0)
-- scf_offset = 0;
-- else
-- scf_offset = 27;
-+ scf_offset = c_idx_nz ? 27 : 0;
- } else {
- scf_offset = 2 + scf_offset;
- }
- }
-- if (significant_coeff_flag_decode_0(s, c_idx, scf_offset) == 1) {
-+ if (significant_coeff_flag_decode_0(s, scf_offset) == 1) {
- significant_coeff_flag_idx[nb_significant_coeff_flag] = 0;
- nb_significant_coeff_flag++;
- }
-@@ -1352,141 +1890,185 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- }
- }
-
-- n_end = nb_significant_coeff_flag;
--
-+ if (nb_significant_coeff_flag != 0) {
-+ const unsigned int gt1_idx_delta = (c_idx_nz << 2) |
-+ ((i != 0 && !c_idx_nz) ? 2 : 0) |
-+ prev_subset_coded;
-+ const unsigned int idx0_gt1 = elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] +
-+ (gt1_idx_delta << 2);
-+ const unsigned int idx_gt2 = elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] +
-+ gt1_idx_delta;
++static AVBufferRef * rpi_buf_pool_alloc(ZcPool * const pool, int size)
++{
++ ZcPoolEnt *const zp = zc_pool_alloc(pool, size);
++ AVBufferRef * buf;
+
-+ const unsigned int x_cg = scan_x_cg[i];
-+ const unsigned int y_cg = scan_y_cg[i];
-+ int16_t * const blk_coeffs = coeffs +
-+ ((x_cg + (y_cg << log2_trafo_size)) << 2);
-+ // This calculation is 'wrong' for log2_traffo_size == 2
-+ // but that doesn't mattor as in this case x_cg & y_cg
-+ // are always 0 so result is correct (0) anyway
-+ const uint8_t * const blk_scale = scale_matrix +
-+ (((x_cg + (y_cg << 3)) << (5 - log2_trafo_size)));
++ if (zp == NULL) {
++ av_log(NULL, AV_LOG_ERROR, "zc_pool_alloc(%d) failed\n", size);
++ goto fail0;
++ }
+
-+ // * THe following code block doesn't deal with these flags:
-+ // (nor did the one it replaces)
-+ //
-+ // cabac_bypass_alignment_enabled_flag
-+ // This should be easy but I can't find a test case
-+ // extended_precision_processing_flag
-+ // This can extend the required precision past 16bits
-+ // so is probably tricky - also no example found yet
++ if ((buf = av_buffer_create(zp->gmem.arm, size, rpi_free_display_buffer, zp, AV_BUFFER_FLAG_READONLY)) == NULL)
++ {
++ av_log(NULL, AV_LOG_ERROR, "av_buffer_create() failed\n");
++ goto fail2;
++ }
+
-+#if USE_N_END_1
-+ if (nb_significant_coeff_flag == 1) {
-+ // There is a small gain to be had from special casing the single
-+ // transform coefficient case. The reduction in complexity
-+ // makes up for the code duplicatioon.
++ return buf;
+
-+ int trans_coeff_level = 1;
-+ int coeff_sign_flag;
-+ int coded_val = 0;
++fail2:
++ zc_pool_free(zp);
++fail0:
++ return NULL;
++}
+
-+ // initialize first elem of coeff_bas_level_greater1_flag
-+ prev_subset_coded = 0;
++static int rpi_get_display_buffer(struct AVCodecContext * const s, AVFrame * const frame)
++{
++ ZcEnv *const zc = s->get_buffer_context;
++ const AVRpiZcFrameGeometry geo = av_rpi_zc_frame_geometry(frame->width, frame->height);
++ const unsigned int size_y = geo.stride_y * geo.height_y;
++ const unsigned int size_c = geo.stride_c * geo.height_c;
++ const unsigned int size_pic = size_y + size_c * 2;
++ AVBufferRef * buf;
++ unsigned int i;
+
-+ if (get_cabac(&s->HEVClc->cc, s->HEVClc->cabac_state + idx0_gt1 + 1)) {
-+ trans_coeff_level = 2;
-+ prev_subset_coded = 1;
-+ coded_val = get_cabac(&s->HEVClc->cc, s->HEVClc->cabac_state + idx_gt2);
-+ }
-
-- if (n_end) {
-- int first_nz_pos_in_cg;
-- int last_nz_pos_in_cg;
-- int c_rice_param = 0;
-- int first_greater1_coeff_idx = -1;
-- uint8_t coeff_abs_level_greater1_flag[8];
-- uint16_t coeff_sign_flag;
-- int sum_abs = 0;
-- int sign_hidden;
-- int sb_type;
-+ // Probably not worth the overhead of starting by22 for just one value
-+ coeff_sign_flag = get_cabac_bypass(&s->HEVClc->cc);
-
-+ if (coded_val)
-+ {
-+ if (!s->ps.sps->persistent_rice_adaptation_enabled_flag) {
-+ trans_coeff_level = 3 + coeff_abs_level_remaining_decode(s, 0);
-+ } else {
-+ uint8_t * const stat_coeff =
-+ lc->stat_coeff + trans_skip_or_bypass + 2 - ((c_idx_nz) << 1);
-+ const unsigned int c_rice_param = *stat_coeff >> 2;
-+ const int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
-
-- // initialize first elem of coeff_bas_level_greater1_flag
-- int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0;
-+ trans_coeff_level = 3 + last_coeff_abs_level_remaining;
-+ update_rice(stat_coeff, last_coeff_abs_level_remaining, c_rice_param);
-+ }
-+ }
-
-- if (s->ps.sps->persistent_rice_adaptation_enabled_flag) {
-- if (!transform_skip_flag && !lc->cu.cu_transquant_bypass_flag)
-- sb_type = 2 * (c_idx == 0 ? 1 : 0);
-- else
-- sb_type = 2 * (c_idx == 0 ? 1 : 0) + 1;
-- c_rice_param = lc->stat_coeff[sb_type] / 4;
-- }
-+ {
-+ const xy_off_t * const xy_off = scan_xy_off + significant_coeff_flag_idx[0];
-+ const int k = (int32_t)(coeff_sign_flag << 31) >> 31;
-+ const unsigned int scale_m = blk_scale[xy_off->scale];
-
-- if (!(i == num_last_subset) && greater1_ctx == 0)
-- ctx_set++;
-- greater1_ctx = 1;
-- last_nz_pos_in_cg = significant_coeff_flag_idx[0];
--
-- for (m = 0; m < (n_end > 8 ? 8 : n_end); m++) {
-- int inc = (ctx_set << 2) + greater1_ctx;
-- coeff_abs_level_greater1_flag[m] =
-- coeff_abs_level_greater1_flag_decode(s, c_idx, inc);
-- if (coeff_abs_level_greater1_flag[m]) {
-- greater1_ctx = 0;
-- if (first_greater1_coeff_idx == -1)
-- first_greater1_coeff_idx = m;
-- } else if (greater1_ctx > 0 && greater1_ctx < 3) {
-- greater1_ctx++;
-+ blk_coeffs[xy_off->coeff] = trans_scale_sat(
-+ (trans_coeff_level ^ k) - k, // Apply sign
-+ scale,
-+ i == 0 && xy_off->coeff == 0 ? dc_scale : scale_m,
-+ shift);
- }
- }
-- first_nz_pos_in_cg = significant_coeff_flag_idx[n_end - 1];
--
-- if (lc->cu.cu_transquant_bypass_flag ||
-- (lc->cu.pred_mode == MODE_INTRA &&
-- s->ps.sps->implicit_rdpcm_enabled_flag && transform_skip_flag &&
-- (pred_mode_intra == 10 || pred_mode_intra == 26 )) ||
-- explicit_rdpcm_flag)
-- sign_hidden = 0;
- else
-- sign_hidden = (last_nz_pos_in_cg - first_nz_pos_in_cg >= 4);
++// printf("Do local alloc: format=%#x, %dx%d: %u\n", frame->format, frame->width, frame->height, size_pic);
++
++ if ((buf = rpi_buf_pool_alloc(&zc->pool, size_pic)) == NULL)
++ {
++ av_log(s, AV_LOG_ERROR, "rpi_get_display_buffer: Failed to get buffer from pool\n");
++ return AVERROR(ENOMEM);
++ }
++
++ for (i = 0; i < AV_NUM_DATA_POINTERS; i++) {
++ frame->buf[i] = NULL;
++ frame->data[i] = NULL;
++ frame->linesize[i] = 0;
++ }
++
++ frame->buf[0] = buf;
++ frame->linesize[0] = geo.stride_y;
++ frame->linesize[1] = geo.stride_c;
++ frame->linesize[2] = geo.stride_c;
++ frame->data[0] = buf->data;
++ frame->data[1] = frame->data[0] + size_y;
++ frame->data[2] = frame->data[1] + size_c;
++ frame->extended_data = frame->data;
++ // Leave extended buf alone
++
++ return 0;
++}
++
++
++#define RPI_GET_BUFFER2 1
++
++int av_rpi_zc_get_buffer2(struct AVCodecContext *s, AVFrame *frame, int flags)
++{
++#if !RPI_GET_BUFFER2
++ return avcodec_default_get_buffer2(s, frame, flags);
++#else
++ int rv;
++
++ if ((s->codec->capabilities & AV_CODEC_CAP_DR1) == 0 ||
++ frame->format != AV_PIX_FMT_YUV420P)
++ {
++// printf("Do default alloc: format=%#x\n", frame->format);
++ rv = avcodec_default_get_buffer2(s, frame, flags);
++ }
++ else
++ {
++ rv = rpi_get_display_buffer(s, frame);
++ }
++
++#if 0
++ printf("%s: %dx%d lsize=%d/%d/%d data=%p/%p/%p bref=%p/%p/%p opaque[0]=%p\n", __func__,
++ frame->width, frame->height,
++ frame->linesize[0], frame->linesize[1], frame->linesize[2],
++ frame->data[0], frame->data[1], frame->data[2],
++ frame->buf[0], frame->buf[1], frame->buf[2],
++ av_buffer_get_opaque(frame->buf[0]));
+#endif
-+ {
-+ int sign_hidden = may_hide_sign;
-+ int levels[16]; // Should be able to get away with int16_t but that fails some tests
-+ uint32_t coeff_sign_flags;
-+ uint32_t coded_vals = 0;
-+ // Sum(abs(level[]))
-+ // In fact we only need the bottom bit and in some future
-+ // version that may be all we calculate
-+ unsigned int sum_abs;
-+
-+ coded_vals = get_greaterx_bits(s, nb_significant_coeff_flag, levels,
-+ &prev_subset_coded, &sum_abs, idx0_gt1, idx_gt2);
-+
-+ if (significant_coeff_flag_idx[0] - significant_coeff_flag_idx[nb_significant_coeff_flag - 1] <= 3)
-+ sign_hidden = 0;
-+
-+ // -- Start bypass block
-+
-+ bypass_start(s);
-+
-+ coeff_sign_flags = coeff_sign_flag_decode_bypass(s, nb_significant_coeff_flag - sign_hidden);
-+
-+ if (coded_vals != 0)
-+ {
-+ const int rice_adaptation_enabled = s->ps.sps->persistent_rice_adaptation_enabled_flag;
-+ uint8_t * stat_coeff = !rice_adaptation_enabled ? NULL :
-+ lc->stat_coeff + trans_skip_or_bypass + 2 - ((c_idx_nz) << 1);
-+ int c_rice_param = !rice_adaptation_enabled ? 0 : *stat_coeff >> 2;
-+ int * level = levels - 1;
-+
-+ do {
-+ {
-+ const unsigned int z = hevc_clz32(coded_vals) + 1;
-+ level += z;
-+ coded_vals <<= z;
-+ }
-
-- if (first_greater1_coeff_idx != -1) {
-- coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += coeff_abs_level_greater2_flag_decode(s, c_idx, ctx_set);
-- }
-- if (!s->ps.pps->sign_data_hiding_flag || !sign_hidden ) {
-- coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag);
-- } else {
-- coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1));
-- }
-+ {
-+ const int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode_bypass(s, c_rice_param);
-+ const int trans_coeff_level = *level + last_coeff_abs_level_remaining + 1;
-+
-+ sum_abs += last_coeff_abs_level_remaining + 1;
-+ *level = trans_coeff_level;
-
-- for (m = 0; m < n_end; m++) {
-- n = significant_coeff_flag_idx[m];
-- GET_COORD(offset, n);
-- if (m < 8) {
-- trans_coeff_level = 1 + coeff_abs_level_greater1_flag[m];
-- if (trans_coeff_level == ((m == first_greater1_coeff_idx) ? 3 : 2)) {
-- int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
--
-- trans_coeff_level += last_coeff_abs_level_remaining;
-- if (trans_coeff_level > (3 << c_rice_param))
-- c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
-- if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
-- int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
-- if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
-- lc->stat_coeff[sb_type]++;
-- else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
-- if (lc->stat_coeff[sb_type] > 0)
-- lc->stat_coeff[sb_type]--;
-- rice_init = 1;
-+ if (stat_coeff != NULL)
-+ update_rice(stat_coeff, last_coeff_abs_level_remaining, c_rice_param);
-+ stat_coeff = NULL;
-+
-+ if (trans_coeff_level > (3 << c_rice_param) &&
-+ (c_rice_param < 4 || rice_adaptation_enabled))
-+ ++c_rice_param;
- }
-- }
-- } else {
-- int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
--
-- trans_coeff_level = 1 + last_coeff_abs_level_remaining;
-- if (trans_coeff_level > (3 << c_rice_param))
-- c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
-- if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
-- int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
-- if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
-- lc->stat_coeff[sb_type]++;
-- else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
-- if (lc->stat_coeff[sb_type] > 0)
-- lc->stat_coeff[sb_type]--;
-- rice_init = 1;
-- }
-+ } while (coded_vals != 0);
- }
-- if (s->ps.pps->sign_data_hiding_flag && sign_hidden) {
-- sum_abs += trans_coeff_level;
-- if (n == first_nz_pos_in_cg && (sum_abs&1))
-- trans_coeff_level = -trans_coeff_level;
-+
-+ // sign_hidden = 0 or 1 so we can combine the tests
-+ if ((sign_hidden & sum_abs) != 0) {
-+ levels[nb_significant_coeff_flag - 1] = -levels[nb_significant_coeff_flag - 1];
- }
-- if (coeff_sign_flag >> 15)
-- trans_coeff_level = -trans_coeff_level;
-- coeff_sign_flag <<= 1;
-- if(!lc->cu.cu_transquant_bypass_flag) {
-- if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
-- if(y_c || x_c || log2_trafo_size < 4) {
-- switch(log2_trafo_size) {
-- case 3: pos = (y_c << 3) + x_c; break;
-- case 4: pos = ((y_c >> 1) << 3) + (x_c >> 1); break;
-- case 5: pos = ((y_c >> 2) << 3) + (x_c >> 2); break;
-- default: pos = (y_c << 2) + x_c; break;
-- }
-- scale_m = scale_matrix[pos];
-- } else {
-- scale_m = dc_scale;
-- }
-+
-+ bypass_finish(s);
-+
-+ // -- Finish bypass block
-+
-+ // Scale loop
-+ {
-+ int m = nb_significant_coeff_flag - 1;
-+
-+ // Deal with DC component (if any) first
-+ if (i == 0 && significant_coeff_flag_idx[m] == 0)
-+ {
-+ const int k = (int32_t)(coeff_sign_flags << m) >> 31;
-+ blk_coeffs[0] = trans_scale_sat(
-+ (levels[m] ^ k) - k, scale, dc_scale, shift);
-+ --m;
- }
-- trans_coeff_level = (trans_coeff_level * (int64_t)scale * (int64_t)scale_m + add) >> shift;
-- if(trans_coeff_level < 0) {
-- if((~trans_coeff_level) & 0xFffffffffff8000)
-- trans_coeff_level = -32768;
-- } else {
-- if(trans_coeff_level & 0xffffffffffff8000)
-- trans_coeff_level = 32767;
-+
-+#if !USE_N_END_1
-+ // If N_END_! set then m was at least 1 initially
-+ if (m >= 0)
++ return rv;
+#endif
-+ {
-+ do {
-+ const xy_off_t * const xy_off = scan_xy_off +
-+ significant_coeff_flag_idx[m];
-+ const int k = (int32_t)(coeff_sign_flags << m) >> 31;
++}
+
-+ blk_coeffs[xy_off->coeff] = trans_scale_sat(
-+ (levels[m] ^ k) - k,
-+ scale,
-+ blk_scale[xy_off->scale],
-+ shift);
-+ } while (--m >= 0);
- }
- }
-- coeffs[y_c * trafo_size + x_c] = trans_coeff_level;
+
- }
- }
-- }
-+ } while ((i = next_subset(s, i, c_idx_nz,
-+ significant_coeff_group_flag, scan_x_cg, scan_y_cg, &prev_sig)) >= 0);
-
- if (lc->cu.cu_transquant_bypass_flag) {
- if (explicit_rdpcm_flag || (s->ps.sps->implicit_rdpcm_enabled_flag &&
-@@ -1496,7 +2078,7 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
- s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode);
- }
- } else {
-- if (transform_skip_flag) {
-+ if (trans_skip_or_bypass) { // Must be trans_skip as we've already dealt with bypass
- int rot = s->ps.sps->transform_skip_rotation_enabled_flag &&
- log2_trafo_size == 2 &&
- lc->cu.pred_mode == MODE_INTRA;
++static AVBufferRef * zc_copy(struct AVCodecContext * const s,
++ const AVFrame * const src)
++{
++ AVFrame dest_frame;
++ AVFrame * const dest = &dest_frame;
++ unsigned int i;
++ uint8_t * psrc, * pdest;
++
++ dest->width = src->width;
++ dest->height = src->height;
++
++ if (rpi_get_display_buffer(s, dest) != 0)
++ {
++ return NULL;
++ }
++
++ for (i = 0, psrc = src->data[0], pdest = dest->data[0];
++ i != dest->height;
++ ++i, psrc += src->linesize[0], pdest += dest->linesize[0])
++ {
++ memcpy(pdest, psrc, dest->width);
++ }
++ for (i = 0, psrc = src->data[1], pdest = dest->data[1];
++ i != dest->height / 2;
++ ++i, psrc += src->linesize[1], pdest += dest->linesize[1])
++ {
++ memcpy(pdest, psrc, dest->width / 2);
++ }
++ for (i = 0, psrc = src->data[2], pdest = dest->data[2];
++ i != dest->height / 2;
++ ++i, psrc += src->linesize[2], pdest += dest->linesize[2])
++ {
++ memcpy(pdest, psrc, dest->width / 2);
++ }
++
++ return dest->buf[0];
++}
++
++
++AVRpiZcRefPtr av_rpi_zc_ref(struct AVCodecContext * const s,
++ const AVFrame * const frame, const int maycopy)
++{
++ assert(s != NULL);
++
++ if (frame->format != AV_PIX_FMT_YUV420P)
++ {
++ av_log(s, AV_LOG_WARNING, "%s: *** Format not YUV420P: %d\n", __func__, frame->format);
++ return NULL;
++ }
++
++ if (frame->buf[1] != NULL)
++ {
++ if (maycopy)
++ {
++ av_log(s, AV_LOG_INFO, "%s: *** Not a single buf frame: copying\n", __func__);
++ return zc_copy(s, frame);
++ }
++ else
++ {
++ av_log(s, AV_LOG_WARNING, "%s: *** Not a single buf frame: NULL\n", __func__);
++ return NULL;
++ }
++ }
++
++ if (pic_gm_ptr(frame->buf[0]) == NULL)
++ {
++ if (maycopy)
++ {
++ av_log(s, AV_LOG_INFO, "%s: *** Not one of our buffers: copying\n", __func__);
++ return zc_copy(s, frame);
++ }
++ else
++ {
++ av_log(s, AV_LOG_WARNING, "%s: *** Not one of our buffers: NULL\n", __func__);
++ return NULL;
++ }
++ }
++
++ return av_buffer_ref(frame->buf[0]);
++}
++
++int av_rpi_zc_vc_handle(const AVRpiZcRefPtr fr_ref)
++{
++ const GPU_MEM_PTR_T * const p = pic_gm_ptr(fr_ref);
++ return p == NULL ? -1 : p->vc_handle;
++}
++
++int av_rpi_zc_numbytes(const AVRpiZcRefPtr fr_ref)
++{
++ const GPU_MEM_PTR_T * const p = pic_gm_ptr(fr_ref);
++ return p == NULL ? 0 : p->numbytes;
++}
++
++void av_rpi_zc_unref(AVRpiZcRefPtr fr_ref)
++{
++ if (fr_ref != NULL)
++ {
++ av_buffer_unref(&fr_ref);
++ }
++}
++
++AVZcEnvPtr av_rpi_zc_env_alloc(void)
++{
++ ZcEnv * const zc = av_mallocz(sizeof(ZcEnv));
++ if (zc == NULL)
++ {
++ av_log(NULL, AV_LOG_ERROR, "av_rpi_zc_env_alloc: Context allocation failed\n");
++ return NULL;
++ }
++
++ zc_pool_init(&zc->pool);
++ return zc;
++}
++
++void av_rpi_zc_env_free(AVZcEnvPtr zc)
++{
++ if (zc != NULL)
++ {
++ zc_pool_destroy(&zc->pool); ;
++ av_free(zc);
++ }
++}
++
++int av_rpi_zc_init(struct AVCodecContext * const s)
++{
++ ZcEnv * const zc = av_rpi_zc_env_alloc();
++ if (zc == NULL)
++ {
++ return AVERROR(ENOMEM);
++ }
++
++ s->get_buffer_context = zc;
++ s->get_buffer2 = av_rpi_zc_get_buffer2;
++ return 0;
++}
++
++void av_rpi_zc_uninit(struct AVCodecContext * const s)
++{
++ if (s->get_buffer2 == av_rpi_zc_get_buffer2)
++ {
++ ZcEnv * const zc = s->get_buffer_context;
++ s->get_buffer2 = avcodec_default_get_buffer2;
++ s->get_buffer_context = NULL;
++ av_rpi_zc_env_free(zc);
++ }
++}
++
++#endif // RPI
++
+diff --git a/libavcodec/rpi_zc.h b/libavcodec/rpi_zc.h
+new file mode 100644
+index 0000000..f0109f4
+--- /dev/null
++++ b/libavcodec/rpi_zc.h
+@@ -0,0 +1,83 @@
++#ifndef LIBAVCODEC_RPI_ZC_H
++#define LIBAVCODEC_RPI_ZC_H
++
++// Zero-Copy frame code for RPi
++// RPi needs Y/U/V planes to be contiguous for display. By default
++// ffmpeg will allocate separated planes so a memcpy is needed before
++// display. This code prodes a method a making ffmpeg allocate a single
++// bit of memory for the frame when can then be refrence counted until
++// display ahs finsihed with it.
++
++#include "libavutil/frame.h"
++#include "libavcodec/avcodec.h"
++
++// "Opaque" pointer to whatever we are using as a buffer reference
++typedef AVBufferRef * AVRpiZcRefPtr;
++
++struct AVZcEnv;
++typedef struct AVZcEnv * AVZcEnvPtr;
++
++typedef struct AVRpiZcFrameGeometry
++{
++ unsigned int stride_y;
++ unsigned int height_y;
++ unsigned int stride_c;
++ unsigned int height_c;
++} AVRpiZcFrameGeometry;
++
++
++AVRpiZcFrameGeometry av_rpi_zc_frame_geometry(
++ const unsigned int video_width, const unsigned int video_height);
++
++// Replacement fn for avctx->get_buffer2
++// Should be set before calling avcodec_decode_open2
++//
++// N.B. in addition to to setting avctx->get_buffer2, avctx->refcounted_frames
++// must be set to 1 as otherwise the buffer info is killed before being returned
++// by avcodec_decode_video2. Note also that this means that the AVFrame that is
++// return must be manually derefed with av_frame_unref. This should be done
++// after av_rpi_zc_ref has been called.
++int av_rpi_zc_get_buffer2(struct AVCodecContext *s, AVFrame *frame, int flags);
++
++// Generate a ZC reference to the buffer(s) in this frame
++// If the buffer doesn't appear to be one allocated by _get_buffer_2
++// then the behaviour depends on maycopy:
++// If maycopy=0 then return NULL
++// If maycopy=1 && the src frame is in a form where we can easily copy
++// the data, then allocate a new buffer and copy the data into it
++// Otherwise return NULL
++AVRpiZcRefPtr av_rpi_zc_ref(struct AVCodecContext * const s,
++ const AVFrame * const frame, const int maycopy);
++
++// Get the vc_handle from the frame ref
++// Returns -1 if ref doesn't look valid
++int av_rpi_zc_vc_handle(const AVRpiZcRefPtr fr_ref);
++// Get the number of bytes allocated from the frame ref
++// Returns 0 if ref doesn't look valid
++int av_rpi_zc_numbytes(const AVRpiZcRefPtr fr_ref);
++
++// Unreference the buffer refed/allocated by _zc_ref
++// If fr_ref is NULL then this will NOP
++void av_rpi_zc_unref(AVRpiZcRefPtr fr_ref);
++
++// Allocate an environment for the buffer pool used by the ZC code
++// This should be put in avctx->get_buffer_context so it can be found by
++// av_rpi_zc_get_buffer2 when it is called from ffmpeg
++AVZcEnvPtr av_rpi_zc_env_alloc(void);
++
++// Allocate the environment used by the ZC code
++void av_rpi_zc_env_free(AVZcEnvPtr);
++
++
++// Init ZC into a context
++// There is nothing magic in this fn - it just packages setting
++// get_buffer2 & get_buffer_context
++int av_rpi_zc_init(struct AVCodecContext * const s);
++
++// Free ZC from a context
++// There is nothing magic in this fn - it just packages unsetting
++// get_buffer2 & get_buffer_context
++void av_rpi_zc_uninit(struct AVCodecContext * const s);
++
++#endif
++
--
2.5.0
+
+From 4d8bccc7b9a611a54253c26dd55fbffbf9db4c48 Mon Sep 17 00:00:00 2001
+From: John Cox
+Date: Tue, 1 Mar 2016 14:21:25 +0000
+Subject: [PATCH 2/2] Set VPU scheduling thread to high priority after creation
+
+---
+ libavcodec/rpi_qpu.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 47 insertions(+), 1 deletion(-)
+
+diff --git a/libavcodec/rpi_qpu.c b/libavcodec/rpi_qpu.c
+index b0c9bc5..ee19231 100644
+--- a/libavcodec/rpi_qpu.c
++++ b/libavcodec/rpi_qpu.c
+@@ -182,9 +182,55 @@ static int gpu_init(volatile struct GPU **gpu) {
+ err = pthread_create(&vpu_thread, NULL, vpu_start, NULL);
+ //printf("Created thread\n");
+ if (err) {
+- printf("Failed to create vpu thread\n");
++ av_log(NULL, AV_LOG_FATAL, "Failed to create vpu thread\n");
+ return -4;
+ }
++
++ {
++ struct sched_param param = {0};
++ int policy = 0;
++
++ if (pthread_getschedparam(vpu_thread, &policy, ¶m) != 0)
++ {
++ av_log(NULL, AV_LOG_ERROR, "Unable to get VPU thread scheduling parameters\n");
++ }
++ else
++ {
++ av_log(NULL, AV_LOG_INFO, "VPU thread: policy=%d (%s), pri=%d\n",
++ policy,
++ policy == SCHED_RR ? "RR" : policy == SCHED_FIFO ? "FIFO" : "???" ,
++ param.sched_priority);
++
++ policy = SCHED_FIFO;
++ param.sched_priority = sched_get_priority_max(SCHED_FIFO);
++
++ av_log(NULL, AV_LOG_INFO, "Attempt to set: policy=%d (%s), pri=%d\n",
++ policy,
++ policy == SCHED_RR ? "RR" : policy == SCHED_FIFO ? "FIFO" : "???" ,
++ param.sched_priority);
++
++ if (pthread_setschedparam(vpu_thread, policy, ¶m) != 0)
++ {
++ av_log(NULL, AV_LOG_ERROR, "Unable to set VPU thread scheduling parameters\n");
++ }
++ else
++ {
++ if (pthread_getschedparam(vpu_thread, &policy, ¶m) != 0)
++ {
++ av_log(NULL, AV_LOG_ERROR, "Unable to get VPU thread scheduling parameters\n");
++ }
++ else
++ {
++ av_log(NULL, AV_LOG_INFO, "VPU thread (after): policy=%d (%s), pri=%d\n",
++ policy,
++ policy == SCHED_RR ? "RR" : policy == SCHED_FIFO ? "FIFO" : "???" ,
++ param.sched_priority);
++ }
++ }
++ }
++
++ }
++
+ }
+ #endif
+
+--
+2.5.0
+
+
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-99.1004-0001-Squashed-commit-of-the-following.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1004-0001-Squashed-commit-of-the-following.patch
new file mode 100644
index 0000000000..5b2f81c1fc
--- /dev/null
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1004-0001-Squashed-commit-of-the-following.patch
@@ -0,0 +1,2181 @@
+From ccb1eff2e6dd1259c6a8ca262076553875c5abe2 Mon Sep 17 00:00:00 2001
+From: John Cox
+Date: Wed, 13 Jan 2016 16:13:33 +0000
+Subject: [PATCH] H.265 residual decode rework (v2)
+
+Rework the cabac decode functions
+Simplify the code flow and variable usage where possible
+
+(Remove profiling and other spurious deltas that were in v1)
+---
+ libavcodec/arm/cabac.h | 155 ++++-
+ libavcodec/arm/hevc_cabac.h | 491 +++++++++++++++
+ libavcodec/arm/hevcdsp_deblock_neon.S | 13 +-
+ libavcodec/arm/hevcdsp_epel_neon.S | 9 +-
+ libavcodec/cabac.h | 9 +-
+ libavcodec/hevc_cabac.c | 1098 +++++++++++++++++++++++++--------
+ 6 files changed, 1510 insertions(+), 265 deletions(-)
+ create mode 100644 libavcodec/arm/hevc_cabac.h
+
+diff --git a/libavcodec/arm/cabac.h b/libavcodec/arm/cabac.h
+index fdbf86b..0a3980a 100644
+--- a/libavcodec/arm/cabac.h
++++ b/libavcodec/arm/cabac.h
+@@ -26,13 +26,34 @@
+ #include "libavutil/internal.h"
+ #include "libavcodec/cabac.h"
+
++
++#if UNCHECKED_BITSTREAM_READER
++#define LOAD_16BITS_BEHI\
++ "ldrh %[tmp] , [%[ptr]] , #2 \n\t"\
++ "rev %[tmp] , %[tmp] \n\t"
++#elif CONFIG_THUMB
++#define LOAD_16BITS_BEHI\
++ "ldr %[tmp] , [%[c], %[end]] \n\t"\
++ "cmp %[tmp] , %[ptr] \n\t"\
++ "it cs \n\t"\
++ "ldrhcs %[tmp] , [%[ptr]] , #2 \n\t"\
++ "rev %[tmp] , %[tmp] \n\t"
++#else
++#define LOAD_16BITS_BEHI\
++ "ldr %[tmp] , [%[c], %[end]] \n\t"\
++ "cmp %[tmp] , %[ptr] \n\t"\
++ "ldrcsh %[tmp] , [%[ptr]] , #2 \n\t"\
++ "rev %[tmp] , %[tmp] \n\t"
++#endif
++
++
+ #define get_cabac_inline get_cabac_inline_arm
+ static av_always_inline int get_cabac_inline_arm(CABACContext *c,
+ uint8_t *const state)
+ {
+ int bit;
++#if 0
+ void *reg_b, *reg_c, *tmp;
+-
+ __asm__ volatile(
+ "ldrb %[bit] , [%[state]] \n\t"
+ "add %[r_b] , %[tables] , %[lps_off] \n\t"
+@@ -100,9 +121,141 @@ static av_always_inline int get_cabac_inline_arm(CABACContext *c,
+ [mlps_off]"I"(H264_MLPS_STATE_OFFSET + 128)
+ : "memory", "cc"
+ );
++#else
++ // *** Not thumb compatible yet
++ unsigned int reg_b, tmp;
++ __asm__ (
++ "ldrb %[bit] , [%[state]] \n\t"
++ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t"
++ "and %[tmp] , %[range] , #0xC0 \n\t"
++ "add %[r_b] , %[r_b] , %[bit] \n\t"
++ "ldrb %[tmp] , [%[r_b] , %[tmp], lsl #1] \n\t"
++// %bit = *state
++// %range = range
++// %tmp = RangeLPS
++ "sub %[range] , %[range] , %[tmp] \n\t"
++
++ "cmp %[low] , %[range] , lsl #17 \n\t"
++ "ittt ge \n\t"
++ "subge %[low] , %[low] , %[range], lsl #17 \n\t"
++ "mvnge %[bit] , %[bit] \n\t"
++ "movge %[range] , %[tmp] \n\t"
++
++ "clz %[tmp] , %[range] \n\t"
++ "sub %[tmp] , #23 \n\t"
++
++ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t"
++ "lsl %[low] , %[low] , %[tmp] \n\t"
++ "lsl %[range] , %[range] , %[tmp] \n\t"
++
++ "strb %[r_b] , [%[state]] \n\t"
++ "lsls %[tmp] , %[low] , #16 \n\t"
++
++ "bne 2f \n\t"
++ LOAD_16BITS_BEHI
++ "lsr %[tmp] , %[tmp] , #15 \n\t"
++ "movw %[r_b] , #0xFFFF \n\t"
++ "sub %[tmp] , %[tmp] , %[r_b] \n\t"
++
++ "rbit %[r_b] , %[low] \n\t"
++ "clz %[r_b] , %[r_b] \n\t"
++ "sub %[r_b] , %[r_b] , #16 \n\t"
++#if CONFIG_THUMB
++ "lsl %[tmp] , %[tmp] , %[r_b] \n\t"
++ "add %[low] , %[low] , %[tmp] \n\t"
++#else
++ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t"
++#endif
++ "2: \n\t"
++ : [bit]"=&r"(bit),
++ [low]"+&r"(c->low),
++ [range]"+&r"(c->range),
++ [r_b]"=&r"(reg_b),
++ [ptr]"+&r"(c->bytestream),
++ [tmp]"=&r"(tmp)
++ : [state]"r"(state),
++ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128),
++ [byte]"M"(offsetof(CABACContext, bytestream)),
++#if !UNCHECKED_BITSTREAM_READER
++ [c]"r"(c),
++ [end]"M"(offsetof(CABACContext, bytestream_end)),
++#endif
++ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET)
++ : "memory", "cc"
++ );
++#endif
+
+ return bit & 1;
+ }
++
++#define get_cabac_bypass get_cabac_bypass_arm
++static inline int get_cabac_bypass_arm(CABACContext * const c)
++{
++ int rv = 0;
++ unsigned int tmp;
++ __asm (
++ "lsl %[low] , #1 \n\t"
++ "cmp %[low] , %[range] , lsl #17 \n\t"
++ "adc %[rv] , %[rv] , #0 \n\t"
++ "it cs \n\t"
++ "subcs %[low] , %[low] , %[range], lsl #17 \n\t"
++ "lsls %[tmp] , %[low] , #16 \n\t"
++ "bne 1f \n\t"
++ LOAD_16BITS_BEHI
++ "add %[low] , %[low] , %[tmp], lsr #15 \n\t"
++ "movw %[tmp] , #0xFFFF \n\t"
++ "sub %[low] , %[low] , %[tmp] \n\t"
++ "1: \n\t"
++ : // Outputs
++ [rv]"+&r"(rv),
++ [low]"+&r"(c->low),
++ [tmp]"=&r"(tmp),
++ [ptr]"+&r"(c->bytestream)
++ : // Inputs
++#if !UNCHECKED_BITSTREAM_READER
++ [c]"r"(c),
++ [end]"M"(offsetof(CABACContext, bytestream_end)),
++#endif
++ [range]"r"(c->range)
++ : "cc"
++ );
++ return rv;
++}
++
++
++#define get_cabac_bypass_sign get_cabac_bypass_sign_arm
++static inline int get_cabac_bypass_sign_arm(CABACContext * const c, int rv)
++{
++ unsigned int tmp;
++ __asm (
++ "lsl %[low] , #1 \n\t"
++ "cmp %[low] , %[range] , lsl #17 \n\t"
++ "ite cc \n\t"
++ "rsbcc %[rv] , %[rv] , #0 \n\t"
++ "subcs %[low] , %[low] , %[range], lsl #17 \n\t"
++ "lsls %[tmp] , %[low] , #16 \n\t"
++ "bne 1f \n\t"
++ LOAD_16BITS_BEHI
++ "add %[low] , %[low] , %[tmp], lsr #15 \n\t"
++ "movw %[tmp] , #0xFFFF \n\t"
++ "sub %[low] , %[low] , %[tmp] \n\t"
++ "1: \n\t"
++ : // Outputs
++ [rv]"+&r"(rv),
++ [low]"+&r"(c->low),
++ [tmp]"=&r"(tmp),
++ [ptr]"+&r"(c->bytestream)
++ : // Inputs
++#if !UNCHECKED_BITSTREAM_READER
++ [c]"r"(c),
++ [end]"M"(offsetof(CABACContext, bytestream_end)),
++#endif
++ [range]"r"(c->range)
++ : "cc"
++ );
++ return rv;
++}
++
+ #endif /* HAVE_ARMV6T2_INLINE */
+
+ #endif /* AVCODEC_ARM_CABAC_H */
+diff --git a/libavcodec/arm/hevc_cabac.h b/libavcodec/arm/hevc_cabac.h
+new file mode 100644
+index 0000000..31d3c59
+--- /dev/null
++++ b/libavcodec/arm/hevc_cabac.h
+@@ -0,0 +1,491 @@
++/*
++ * This file is part of FFmpeg.
++ *
++ * FFmpeg is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++ *
++ * FFmpeg is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++ *
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with FFmpeg; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ */
++
++#ifndef AVCODEC_ARM_HEVC_CABAC_H
++#define AVCODEC_ARM_HEVC_CABAC_H
++
++#include "config.h"
++#if HAVE_ARMV6T2_INLINE
++
++#define hevc_mem_bits32 hevc_mem_bits32_arm
++static inline uint32_t hevc_mem_bits32_arm(const void * p, const unsigned int bits)
++{
++ unsigned int n;
++ __asm__ (
++ "rev %[n], %[x] \n\t"
++ : [n]"=r"(n)
++ : [x]"r"(*(const uint32_t *)((const uint8_t *)p + (bits >> 3)))
++ :
++ );
++ return n << (bits & 7);
++}
++
++
++// ---------------------------------------------------------------------------
++//
++// Helper fns - little bits of code where ARM has an instraction that the
++// compiler doesn't know about / use
++
++#define trans_scale_sat trans_scale_sat_arm
++static inline int trans_scale_sat_arm(const int level, const unsigned int scale, const unsigned int scale_m, const unsigned int shift)
++{
++ int rv;
++ int t = ((level * (int)(scale * scale_m)) >> shift) + 1;
++
++ __asm__ (
++ "ssat %[rv], #16, %[t], ASR #1 \n\t"
++ : [rv]"=r"(rv)
++ : [t]"r"(t)
++ :
++ );
++ return rv;
++}
++
++#define update_rice update_rice_arm
++static inline void update_rice_arm(uint8_t * const stat_coeff,
++ const unsigned int last_coeff_abs_level_remaining,
++ const unsigned int c_rice_param)
++{
++ int t;
++ __asm__ (
++ "lsl %[t], %[coeff], #1 \n\t"
++ "lsrs %[t], %[t], %[shift] \n\t"
++ "it eq \n\t"
++ "subeq %[stat], %[stat], #1 \n\t"
++ "cmp %[t], #6 \n\t"
++ "adc %[stat], %[stat], #0 \n\t"
++ "usat %[stat], #8, %[stat] \n\t"
++ : [stat]"+&r"(*stat_coeff),
++ [t]"=&r"(t)
++ : [coeff]"r"(last_coeff_abs_level_remaining),
++ [shift]"r"(c_rice_param)
++ : "cc"
++ );
++}
++
++// ---------------------------------------------------------------------------
++//
++// CABAC get loops
++//
++// Where the loop is simple enough we can normally do 10-30% better than the
++// compiler
++
++// Get the residual greater than 1 bits
++
++#define get_cabac_greater1_bits get_cabac_greater1_bits_arm
++static inline unsigned int get_cabac_greater1_bits_arm(CABACContext * const c, const unsigned int n,
++ uint8_t * const state0)
++{
++ unsigned int i, reg_b, st, tmp, bit, rv;
++ __asm__ (
++ "mov %[i] , #0 \n\t"
++ "mov %[rv] , #0 \n\t"
++ "1: \n\t"
++ "add %[i] , %[i] , #1 \n\t"
++ "cmp %[rv] , #0 \n\t"
++ "ite eq \n\t"
++ "usateq %[st] , #2 , %[i] \n\t"
++ "movne %[st] , #0 \n\t"
++
++ "ldrb %[bit] , [%[state0], %[st]] \n\t"
++ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t"
++ "and %[tmp] , %[range] , #0xC0 \n\t"
++ "add %[r_b] , %[r_b] , %[bit] \n\t"
++ "ldrb %[tmp] , [%[r_b], %[tmp], lsl #1] \n\t"
++ "sub %[range] , %[range] , %[tmp] \n\t"
++
++ "cmp %[low] , %[range], lsl #17 \n\t"
++ "ittt ge \n\t"
++ "subge %[low] , %[low] , %[range], lsl #17 \n\t"
++ "mvnge %[bit] , %[bit] \n\t"
++ "movge %[range] , %[tmp] \n\t"
++
++ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t"
++ "and %[bit] , %[bit] , #1 \n\t"
++ "orr %[rv] , %[bit] , %[rv], lsl #1 \n\t"
++
++ "clz %[tmp] , %[range] \n\t"
++ "sub %[tmp] , #23 \n\t"
++
++ "lsl %[low] , %[low] , %[tmp] \n\t"
++ "lsl %[range] , %[range] , %[tmp] \n\t"
++
++ "strb %[r_b] , [%[state0], %[st]] \n\t"
++// There is a small speed gain from combining both conditions, using a single
++// branch and then working out what that meant later
++ "lsls %[tmp] , %[low] , #16 \n\t"
++ "it ne \n\t"
++ "cmpne %[n] , %[i] \n\t"
++ "bne 1b \n\t"
++
++// If reload is not required then we must have run out of flags to decode
++ "tst %[tmp] , %[tmp] \n\t"
++ "bne 2f \n\t"
++
++// Do reload
++ "ldrh %[tmp] , [%[bptr]] , #2 \n\t"
++ "movw %[r_b] , #0xFFFF \n\t"
++ "rev %[tmp] , %[tmp] \n\t"
++ "rsb %[tmp] , %[r_b] , %[tmp], lsr #15 \n\t"
++
++ "rbit %[r_b] , %[low] \n\t"
++ "clz %[r_b] , %[r_b] \n\t"
++ "sub %[r_b] , %[r_b] , #16 \n\t"
++
++#if CONFIG_THUMB
++ "lsl %[tmp] , %[tmp] , %[r_b] \n\t"
++ "add %[low] , %[low] , %[tmp] \n\t"
++#else
++ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t"
++#endif
++
++ "cmp %[n] , %[i] \n\t"
++ "bne 1b \n\t"
++ "2: \n\t"
++ : [bit]"=&r"(bit),
++ [low]"+&r"(c->low),
++ [range]"+&r"(c->range),
++ [r_b]"=&r"(reg_b),
++ [bptr]"+&r"(c->bytestream),
++ [i]"=&r"(i),
++ [tmp]"=&r"(tmp),
++ [st]"=&r"(st),
++ [rv]"=&r"(rv)
++ : [state0]"r"(state0),
++ [n]"r"(n),
++ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128),
++ [byte]"M"(offsetof(CABACContext, bytestream)),
++ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET)
++ : "memory", "cc"
++ );
++ return rv;
++}
++
++
++// n must be > 0 on entry
++#define get_cabac_sig_coeff_flag_idxs get_cabac_sig_coeff_flag_idxs_arm
++static inline uint8_t * get_cabac_sig_coeff_flag_idxs_arm(CABACContext * const c, uint8_t * const state0,
++ unsigned int n,
++ const uint8_t const * ctx_map,
++ uint8_t * p)
++{
++ unsigned int reg_b, tmp, st, bit;
++ __asm__ (
++ "1: \n\t"
++// Get bin from map
++ "ldrb %[st] , [%[ctx_map], %[n]] \n\t"
++
++// Load state & ranges
++ "sub %[r_b] , %[mlps_tables], %[lps_off] \n\t"
++ "ldrb %[bit] , [%[state0], %[st]] \n\t"
++ "and %[tmp] , %[range] , #0xC0 \n\t"
++ "add %[r_b] , %[r_b] , %[tmp], lsl #1 \n\t"
++ "ldrb %[tmp] , [%[r_b], %[bit]] \n\t"
++ "sub %[range] , %[range] , %[tmp] \n\t"
++
++ "cmp %[low] , %[range], lsl #17 \n\t"
++ "ittt ge \n\t"
++ "subge %[low] , %[low] , %[range], lsl #17 \n\t"
++ "mvnge %[bit] , %[bit] \n\t"
++ "movge %[range] , %[tmp] \n\t"
++
++ "ldrb %[r_b] , [%[mlps_tables], %[bit]] \n\t"
++ "tst %[bit] , #1 \n\t"
++// GCC asm seems to need strbne written differently for thumb and arm
++#if CONFIG_THUMB
++ "it ne \n\t"
++ "strbne %[n] , [%[idx]] , #1 \n\t"
++#else
++ "strneb %[n] , [%[idx]] , #1 \n\t"
++#endif
++
++// Renorm
++ "clz %[tmp] , %[range] \n\t"
++ "sub %[tmp] , #23 \n\t"
++ "lsl %[low] , %[low] , %[tmp] \n\t"
++ "lsl %[range] , %[range] , %[tmp] \n\t"
++
++ "strb %[r_b] , [%[state0], %[st]] \n\t"
++// There is a small speed gain from combining both conditions, using a single
++// branch and then working out what that meant later
++ "subs %[n] , %[n] , #1 \n\t"
++#if CONFIG_THUMB
++ "itt ne \n\t"
++ "lslsne %[tmp] , %[low] , #16 \n\t"
++ "bne 1b \n\t"
++#else
++ "lslnes %[tmp] , %[low] , #16 \n\t"
++ "bne 1b \n\t"
++#endif
++
++// If we have bits left then n must be 0 so give up now
++ "lsls %[tmp] , %[low] , #16 \n\t"
++ "bne 2f \n\t"
++
++// Do reload
++ "ldrh %[tmp] , [%[bptr]] , #2 \n\t"
++ "movw %[r_b] , #0xFFFF \n\t"
++ "rev %[tmp] , %[tmp] \n\t"
++ "rsb %[tmp] , %[r_b] , %[tmp], lsr #15 \n\t"
++
++ "rbit %[r_b] , %[low] \n\t"
++ "clz %[r_b] , %[r_b] \n\t"
++ "sub %[r_b] , %[r_b] , #16 \n\t"
++
++#if CONFIG_THUMB
++ "lsl %[tmp] , %[tmp] , %[r_b] \n\t"
++ "add %[low] , %[low] , %[tmp] \n\t"
++#else
++ "add %[low] , %[low] , %[tmp], lsl %[r_b] \n\t"
++#endif
++
++// Check to see if we still have more to do
++ "cmp %[n] , #0 \n\t"
++ "bne 1b \n\t"
++ "2: \n\t"
++ : [bit]"=&r"(bit),
++ [low]"+&r"(c->low),
++ [range]"+&r"(c->range),
++ [r_b]"=&r"(reg_b),
++ [bptr]"+&r"(c->bytestream),
++ [idx]"+&r"(p),
++ [n]"+&r"(n),
++ [tmp]"=&r"(tmp),
++ [st]"=&r"(st)
++ : [state0]"r"(state0),
++ [ctx_map]"r"(ctx_map),
++ [mlps_tables]"r"(ff_h264_cabac_tables + H264_MLPS_STATE_OFFSET + 128),
++ [byte]"M"(offsetof(CABACContext, bytestream)),
++ [lps_off]"I"((H264_MLPS_STATE_OFFSET + 128) - H264_LPS_RANGE_OFFSET)
++ : "memory", "cc"
++ );
++
++ return p;
++}
++
++// ---------------------------------------------------------------------------
++//
++// CABAC_BY22 functions
++//
++// By and large these are (at best) no faster than their C equivalents - the
++// only one worth having is _peek where we do a slightly better job than the
++// compiler
++//
++// The others have been stashed here for reference in case larger scale asm
++// is attempted in which case they might be a useful base
++
++
++#define get_cabac_by22_peek get_cabac_by22_peek_arm
++static inline uint32_t get_cabac_by22_peek_arm(const CABACContext *const c)
++{
++ uint32_t rv, tmp;
++ __asm__ (
++ "bic %[rv] , %[low], #1 \n\t"
++ "cmp %[inv] , #0 \n\t"
++ "it ne \n\t"
++ "umullne %[tmp] , %[rv] , %[inv], %[rv] \n\t"
++ : // Outputs
++ [rv]"=&r"(rv),
++ [tmp]"=r"(tmp)
++ : // Inputs
++ [low]"r"(c->low),
++ [inv]"r"(c->range)
++ : // Clobbers
++ "cc"
++ );
++ return rv << 1;
++}
++
++#if 0
++
++// ***** Slower than the C :-(
++#define get_cabac_by22_flush get_cabac_by22_flush_arm
++static inline void get_cabac_by22_flush_arm(CABACContext *const c, const unsigned int n, const uint32_t val)
++{
++ uint32_t m, tmp;
++ __asm__ (
++ "add %[bits], %[bits], %[n] \n\t"
++ "ldr %[m], [%[ptr], %[bits], lsr #3] \n\t"
++
++ "rsb %[tmp], %[n], #32 \n\t"
++ "lsr %[tmp], %[val], %[tmp] \n\t"
++ "mul %[tmp], %[range], %[tmp] \n\t"
++
++ "rev %[m], %[m] \n\t"
++
++ "lsl %[tmp], %[tmp], #23 \n\t"
++ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t"
++
++ "and %[tmp], %[bits], #7 \n\t"
++ "lsl %[m], %[m], %[tmp] \n\t"
++
++ "orr %[low], %[low], %[m], lsr #9 \n\t"
++ : // Outputs
++ [m]"=&r"(m),
++ [tmp]"=&r"(tmp),
++ [bits]"+&r"(c->by22.bits),
++ [low]"+&r"(c->low)
++ : // Inputs
++ [n]"r"(n),
++ [val]"r"(val),
++ [inv]"r"(c->range),
++ [range]"r"(c->by22.range),
++ [ptr]"r"(c->bytestream)
++ : // Clobbers
++ );
++}
++
++
++// Works but slower than C
++#define coeff_abs_level_remaining_decode_by22(c,r) coeff_abs_level_remaining_decode_by22_arm(c, r)
++static int coeff_abs_level_remaining_decode_by22_arm(CABACContext * const c, const unsigned int c_rice_param)
++{
++ uint32_t n, val, tmp, level;
++
++// PROFILE_START();
++
++ __asm__ (
++ // Peek
++ "bic %[val], %[low], #1 \n\t"
++ "cmp %[inv], #0 \n\t"
++ "umullne %[tmp], %[val], %[inv], %[val] \n\t"
++ "lsl %[val], %[val], #1 \n\t"
++
++ // Count bits (n = prefix)
++ "mvn %[n], %[val] \n\t"
++ "clz %[n], %[n] \n\t"
++
++ "lsl %[level], %[val], %[n] \n\t"
++ "subs %[tmp], %[n], #3 \n\t"
++ "blo 2f \n\t"
++
++ // prefix >= 3
++ // < tmp = prefix - 3
++ // > tmp = prefix + rice - 3
++ "add %[tmp], %[tmp], %[rice] \n\t"
++ // > n = prefix * 2 + rice - 3
++ "add %[n], %[tmp], %[n] \n\t"
++ "cmp %[n], #21 \n\t"
++ "bhi 3f \n\t"
++
++ "orr %[level], %[level], #0x80000000 \n\t"
++ "rsb %[tmp], %[tmp], #31 \n\t"
++ "lsr %[level], %[level], %[tmp] \n\t"
++
++ "mov %[tmp], #2 \n\t"
++ "add %[level], %[level], %[tmp], lsl %[rice] \n\t"
++ "b 1f \n\t"
++
++ // > 22 bits used in total - need reload
++ "3: \n\t"
++
++ // Stash prefix + rice - 3 in level (only spare reg)
++ "mov %[level], %[tmp] \n\t"
++ // Restore n to flush value (prefix)
++ "sub %[n], %[n], %[tmp] \n\t"
++
++ // Flush + reload
++
++// "rsb %[tmp], %[n], #32 \n\t"
++// "lsr %[tmp], %[val], %[tmp] \n\t"
++// "mul %[tmp], %[range], %[tmp] \n\t"
++
++ // As it happens we know that all the bits we are flushing are 1
++ // so we can cheat slightly
++ "rsb %[tmp], %[range], %[range], lsl %[n] \n\t"
++ "lsl %[tmp], %[tmp], #23 \n\t"
++ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t"
++
++ "add %[bits], %[bits], %[n] \n\t"
++ "ldr %[n], [%[ptr], %[bits], lsr #3] \n\t"
++ "rev %[n], %[n] \n\t"
++ "and %[tmp], %[bits], #7 \n\t"
++ "lsl %[n], %[n], %[tmp] \n\t"
++
++ "orr %[low], %[low], %[n], lsr #9 \n\t"
++
++ // (reload)
++
++ "bic %[val], %[low], #1 \n\t"
++ "cmp %[inv], #0 \n\t"
++ "umullne %[tmp], %[val], %[inv], %[val] \n\t"
++ "lsl %[val], %[val], #1 \n\t"
++
++ // Build value
++
++ "mov %[n], %[level] \n\t"
++
++ "orr %[tmp], %[val], #0x80000000 \n\t"
++ "rsb %[level], %[level], #31 \n\t"
++ "lsr %[level], %[tmp], %[level] \n\t"
++
++ "mov %[tmp], #2 \n\t"
++ "add %[level], %[level], %[tmp], lsl %[rice] \n\t"
++ "b 1f \n\t"
++
++ // prefix < 3
++ "2: \n\t"
++ "rsb %[tmp], %[rice], #31 \n\t"
++ "lsr %[level], %[level], %[tmp] \n\t"
++ "orr %[level], %[level], %[n], lsl %[rice] \n\t"
++ "add %[n], %[n], %[rice] \n\t"
++
++ "1: \n\t"
++ // Flush
++ "add %[n], %[n], #1 \n\t"
++
++ "rsb %[tmp], %[n], #32 \n\t"
++ "lsr %[tmp], %[val], %[tmp] \n\t"
++
++ "add %[bits], %[bits], %[n] \n\t"
++ "ldr %[val], [%[ptr], %[bits], lsr #3] \n\t"
++
++ "mul %[tmp], %[range], %[tmp] \n\t"
++ "lsl %[tmp], %[tmp], #23 \n\t"
++ "rsb %[low], %[tmp], %[low], lsl %[n] \n\t"
++
++ "rev %[val], %[val] \n\t"
++ "and %[tmp], %[bits], #7 \n\t"
++ "lsl %[val], %[val], %[tmp] \n\t"
++
++ "orr %[low], %[low], %[val], lsr #9 \n\t"
++ : // Outputs
++ [level]"=&r"(level),
++ [n]"=&r"(n),
++ [val]"=&r"(val),
++ [tmp]"=&r"(tmp),
++ [bits]"+&r"(c->by22.bits),
++ [low]"+&r"(c->low)
++ : // Inputs
++ [rice]"r"(c_rice_param),
++ [inv]"r"(c->range),
++ [range]"r"(c->by22.range),
++ [ptr]"r"(c->bytestream)
++ : // Clobbers
++ "cc"
++ );
++
++// PROFILE_ACC(residual_abs);
++
++ return level;
++}
++#endif
++
++#endif /* HAVE_ARMV6T2_INLINE */
++
++#endif /* AVCODEC_ARM_HEVC_CABAC_H */
+diff --git a/libavcodec/arm/hevcdsp_deblock_neon.S b/libavcodec/arm/hevcdsp_deblock_neon.S
+index bad4589..a088cc3 100644
+--- a/libavcodec/arm/hevcdsp_deblock_neon.S
++++ b/libavcodec/arm/hevcdsp_deblock_neon.S
+@@ -409,10 +409,12 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
+ beq 90f
+
+ tst a3, #1
++ itee ne
+ ldrne a3, [v5, #0] @ curr->mv[0]
+ ldreq a3, [v5, #4] @ curr->mv[1]
+ moveq v1, v2
+ tst v8, #1
++ itee ne
+ ldrne v8, [v6, #0] @ neigh->mv[0]
+ ldreq v8, [v6, #4] @ neigh->mv[1]
+ moveq v3, v4
+@@ -424,9 +426,14 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
+ sel a3, a3, ip
+ ands a3, a3, lr
+ @ drop through
+-10: movne a3, #1
++10: it ne
++ movne a3, #1
+ 11: subs a2, a2, #1
+-12: strbhs a3, [v7], a4
++12:
++A strbhs a3, [v7], a4
++T itt hs
++T strbhs a3, [v7]
++T addhs v7, v7, a4
+ subs a2, a2, #1
+ bhs 12b
+
+@@ -442,6 +449,7 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
+ bne 10b
+
+ teq v1, v3
++ it eq
+ teqeq v2, v4
+ bne 40f
+ teq v1, v2
+@@ -487,6 +495,7 @@ function ff_hevc_deblocking_boundary_strengths_neon, export=1
+ b 10b
+
+ 40: teq v1, v4
++ ite eq
+ teqeq v2, v3
+ bne 10b
+
+diff --git a/libavcodec/arm/hevcdsp_epel_neon.S b/libavcodec/arm/hevcdsp_epel_neon.S
+index 516ae5b..00eab9e 100644
+--- a/libavcodec/arm/hevcdsp_epel_neon.S
++++ b/libavcodec/arm/hevcdsp_epel_neon.S
+@@ -110,7 +110,9 @@ function ff_hevc_put_epel_h_neon_8, export=1
+ sub r7, #1
+ lsl r7, #2
+ vpush {d8-d15}
+- adrl r12, epel_coeffs
++@ adr reaches if we are in thumb mode but not in arm
++T adr r12, epel_coeffs
++A adrl r12, epel_coeffs
+ add r7, r12
+ sub r1, #1
+ lsl r4, #1
+@@ -170,7 +172,8 @@ function ff_hevc_put_epel_v_neon_8, export=1
+ sub r7, #1
+ lsl r7, #2
+ vpush {d8-d15}
+- adrl r12, epel_coeffs
++T adr r12, epel_coeffs
++A adrl r12, epel_coeffs
+ add r7, r12
+ load_coeffs_16b r7
+ sub r1, r2
+@@ -246,7 +249,7 @@ function ff_hevc_put_epel_hv_neon_8, export=1
+ sub r7, #1
+ lsl r7, #2
+ vpush {d8-d15}
+- adrl r12, epel_coeffs
++ adr r12, epel_coeffs
+ sub r6, #1
+ lsl r6, #2
+ add r6, r12 // mx epel coeff offset
+diff --git a/libavcodec/cabac.h b/libavcodec/cabac.h
+index 1bf1c62..ccfa991 100644
+--- a/libavcodec/cabac.h
++++ b/libavcodec/cabac.h
+@@ -43,7 +43,14 @@ extern const uint8_t ff_h264_cabac_tables[512 + 4*2*64 + 4*64 + 63];
+ typedef struct CABACContext{
+ int low;
+ int range;
+- int outstanding_count;
++ union
++ {
++ int outstanding_count;
++ struct {
++ uint16_t bits;
++ uint16_t range;
++ } by22;
++ };
+ const uint8_t *bytestream_start;
+ const uint8_t *bytestream;
+ const uint8_t *bytestream_end;
+diff --git a/libavcodec/hevc_cabac.c b/libavcodec/hevc_cabac.c
+index 271e17a..4caf720 100644
+--- a/libavcodec/hevc_cabac.c
++++ b/libavcodec/hevc_cabac.c
+@@ -21,14 +21,72 @@
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
++#define UNCHECKED_BITSTREAM_READER 1
++
+ #include "libavutil/attributes.h"
+ #include "libavutil/common.h"
+
+-#include "cabac_functions.h"
+ #include "hevc.h"
++#include "cabac_functions.h"
++
++// BY22 is probably faster than simple bypass if the processor has
++// either a fast 32-bit divide or a fast 32x32->64[63:32] instruction
++// x86 has fast int divide
++// Arm doesn't have divide or general fast 64 bit, but does have the multiply
++// * Beware: ARCH_xxx isn't set if configure --disable-asm is used
++#define USE_BY22 (HAVE_FAST_64BIT || ARCH_ARM || ARCH_X86)
++// Use native divide if we have a fast one - otherwise use mpy 1/x
++// x86 has a fast integer divide - arm doesn't - unsure about other
++// architectures
++#define USE_BY22_DIV ARCH_X86
++
++// Special case blocks with a single significant ceoff
++// Decreases the complexity of the code for a common case but increases the
++// code size.
++#define USE_N_END_1 1
++
++#if ARCH_ARM
++#include "arm/hevc_cabac.h"
++#endif
+
+ #define CABAC_MAX_BIN 31
+
++
++#if USE_BY22 && !USE_BY22_DIV
++#define I(x) (uint32_t)((0x10000000000ULL / (uint64_t)(x)) + 1ULL)
++
++static const uint32_t cabac_by22_inv_range[256] = {
++ 0, I(257), I(258), I(259),
++ I(260), I(261), I(262), I(263), I(264), I(265), I(266), I(267), I(268), I(269),
++ I(270), I(271), I(272), I(273), I(274), I(275), I(276), I(277), I(278), I(279),
++ I(280), I(281), I(282), I(283), I(284), I(285), I(286), I(287), I(288), I(289),
++ I(290), I(291), I(292), I(293), I(294), I(295), I(296), I(297), I(298), I(299),
++ I(300), I(301), I(302), I(303), I(304), I(305), I(306), I(307), I(308), I(309),
++ I(310), I(311), I(312), I(313), I(314), I(315), I(316), I(317), I(318), I(319),
++ I(320), I(321), I(322), I(323), I(324), I(325), I(326), I(327), I(328), I(329),
++ I(330), I(331), I(332), I(333), I(334), I(335), I(336), I(337), I(338), I(339),
++ I(340), I(341), I(342), I(343), I(344), I(345), I(346), I(347), I(348), I(349),
++ I(350), I(351), I(352), I(353), I(354), I(355), I(356), I(357), I(358), I(359),
++ I(360), I(361), I(362), I(363), I(364), I(365), I(366), I(367), I(368), I(369),
++ I(370), I(371), I(372), I(373), I(374), I(375), I(376), I(377), I(378), I(379),
++ I(380), I(381), I(382), I(383), I(384), I(385), I(386), I(387), I(388), I(389),
++ I(390), I(391), I(392), I(393), I(394), I(395), I(396), I(397), I(398), I(399),
++ I(400), I(401), I(402), I(403), I(404), I(405), I(406), I(407), I(408), I(409),
++ I(410), I(411), I(412), I(413), I(414), I(415), I(416), I(417), I(418), I(419),
++ I(420), I(421), I(422), I(423), I(424), I(425), I(426), I(427), I(428), I(429),
++ I(430), I(431), I(432), I(433), I(434), I(435), I(436), I(437), I(438), I(439),
++ I(440), I(441), I(442), I(443), I(444), I(445), I(446), I(447), I(448), I(449),
++ I(450), I(451), I(452), I(453), I(454), I(455), I(456), I(457), I(458), I(459),
++ I(460), I(461), I(462), I(463), I(464), I(465), I(466), I(467), I(468), I(469),
++ I(470), I(471), I(472), I(473), I(474), I(475), I(476), I(477), I(478), I(479),
++ I(480), I(481), I(482), I(483), I(484), I(485), I(486), I(487), I(488), I(489),
++ I(490), I(491), I(492), I(493), I(494), I(495), I(496), I(497), I(498), I(499),
++ I(500), I(501), I(502), I(503), I(504), I(505), I(506), I(507), I(508), I(509),
++ I(510), I(511)
++};
++#undef I
++#endif // USE_BY22
++
+ /**
+ * number of bin by SyntaxElement.
+ */
+@@ -445,6 +503,211 @@ static const uint8_t diag_scan8x8_inv[8][8] = {
+ { 28, 36, 43, 49, 54, 58, 61, 63, },
+ };
+
++
++typedef struct
++{
++ uint16_t coeff;
++ uint16_t scale;
++} xy_off_t;
++
++#define XYT_C(x,y,t) ((x) + ((y) << (t)))
++#define SCALE_TRAFO(t) ((t) > 3 ? 3 : (t))
++#define SCALE_SHR(t) ((t) - SCALE_TRAFO(t))
++#define XYT_S(x,y,t) (((x) >> SCALE_SHR(t)) + (((y) >> SCALE_SHR(t)) << SCALE_TRAFO(t)))
++
++#define XYT(x,y,t) {XYT_C(x,y,t), XYT_S(x,y,t)}
++
++#define OFF_DIAG(t) {\
++ XYT(0,0,t), XYT(0,1,t), XYT(1,0,t), XYT(0,2,t),\
++ XYT(1,1,t), XYT(2,0,t), XYT(0,3,t), XYT(1,2,t),\
++ XYT(2,1,t), XYT(3,0,t), XYT(1,3,t), XYT(2,2,t),\
++ XYT(3,1,t), XYT(2,3,t), XYT(3,2,t), XYT(3,3,t)\
++}
++
++#define OFF_HORIZ(t) {\
++ XYT(0,0,t), XYT(1,0,t), XYT(2,0,t), XYT(3,0,t),\
++ XYT(0,1,t), XYT(1,1,t), XYT(2,1,t), XYT(3,1,t),\
++ XYT(0,2,t), XYT(1,2,t), XYT(2,2,t), XYT(3,2,t),\
++ XYT(0,3,t), XYT(1,3,t), XYT(2,3,t), XYT(3,3,t)\
++}
++
++#define OFF_VERT(t) {\
++ XYT(0,0,t), XYT(0,1,t), XYT(0,2,t), XYT(0,3,t),\
++ XYT(1,0,t), XYT(1,1,t), XYT(1,2,t), XYT(1,3,t),\
++ XYT(2,0,t), XYT(2,1,t), XYT(2,2,t), XYT(2,3,t),\
++ XYT(3,0,t), XYT(3,1,t), XYT(3,2,t), XYT(3,3,t)\
++}
++
++static const xy_off_t off_xys[3][4][16] =
++{
++ {OFF_DIAG(2), OFF_DIAG(3), OFF_DIAG(4), OFF_DIAG(5)},
++ {OFF_HORIZ(2), OFF_HORIZ(3), OFF_HORIZ(4), OFF_HORIZ(5)},
++ {OFF_VERT(2), OFF_VERT(3), OFF_VERT(4), OFF_VERT(5)}
++};
++
++
++// Helper fns
++#ifndef hevc_mem_bits32
++static av_always_inline uint32_t hevc_mem_bits32(const void * buf, const unsigned int offset)
++{
++ return AV_RB32((const uint8_t *)buf + (offset >> 3)) << (offset & 7);
++}
++#endif
++
++#if AV_GCC_VERSION_AT_LEAST(3,4) && !defined(hevc_clz32)
++#define hevc_clz32 hevc_clz32_builtin
++static av_always_inline unsigned int hevc_clz32_builtin(const uint32_t x)
++{
++ // __builtin_clz says it works on ints - so adjust if int is >32 bits long
++ return __builtin_clz(x) - (sizeof(int) * 8 - 32);
++}
++#endif
++
++// It is unlikely that we will ever need this but include for completeness
++#ifndef hevc_clz32
++static inline unsigned int hevc_clz32(unsigned int x)
++{
++ unsigned int n = 1;
++ if ((x & 0xffff0000) == 0) {
++ n += 16;
++ x <<= 16;
++ }
++ if ((x & 0xff000000) == 0) {
++ n += 8;
++ x <<= 8;
++ }
++ if ((x & 0xf0000000) == 0) {
++ n += 4;
++ x <<= 4;
++ }
++ if ((x & 0xc0000000) == 0) {
++ n += 2;
++ x <<= 2;
++ }
++ return n - ((x >> 31) & 1);
++}
++#endif
++
++
++#if !USE_BY22
++// If no by22 then _by22 functions will revert to normal and so _peek/_flush
++// will no longer be called but the setup calls will still exist and we want
++// to null them out
++#define bypass_start(s)
++#define bypass_finish(s)
++#else
++// Use BY22 for residual bypass block
++
++#define bypass_start(s) get_cabac_by22_start(&s->HEVClc->cc)
++#define bypass_finish(s) get_cabac_by22_finish(&s->HEVClc->cc)
++
++// BY22 notes that bypass is simply a divide into the bitstream and so we
++// can peek out large quantities of bits at one and treat the result as if
++// it was VLC. In many cases this will lead to O(1) processing rather than
++// O(n) though the setup and teardown is sufficiently expensive that it is
++// only worth using if we expect to be dealing with more than a few bits
++// The definition of "a few bits" will vary from platform to platform but
++// tests on ARM show that it probably isn't worth it for a single coded
++// residual, but is for >1 - this is probaly reinforced that if there are
++// more residuals then they are likely to be bigger and this will make the
++// O(1) nature of the code more worthwhile.
++
++
++#if !USE_BY22_DIV
++// * 1/x @ 32 bits gets us 22 bits of accuracy
++#define CABAC_BY22_PEEK_BITS 22
++#else
++// A real 32-bit divide gets us another bit
++// If we have a 64 bit int & a unit time divider then we should get a lot
++// of bits (55) but that is untested and it is unclear if it would give
++// us a large advantage
++#define CABAC_BY22_PEEK_BITS 23
++#endif
++
++// Bypass block start
++// Must be called before _by22_peek is used as it sets the CABAC environment
++// into the correct state. _by22_finish must be called to return to 'normal'
++// (i.e. non-bypass) cabac decoding
++static inline void get_cabac_by22_start(CABACContext * const c)
++{
++ const unsigned int bits = __builtin_ctz(c->low);
++ const uint32_t m = hevc_mem_bits32(c->bytestream, 0);
++ uint32_t x = (c->low << (22 - CABAC_BITS)) ^ ((m ^ 0x80000000U) >> (9 + CABAC_BITS - bits));
++#if !USE_BY22_DIV
++ const uint32_t inv = cabac_by22_inv_range[c->range & 0xff];
++#endif
++
++ c->bytestream -= (CABAC_BITS / 8);
++ c->by22.bits = bits;
++#if !USE_BY22_DIV
++ c->by22.range = c->range;
++ c->range = inv;
++#endif
++ c->low = x;
++}
++
++// Bypass block finish
++// Must be called at the end of the bypass block to return to normal operation
++static inline void get_cabac_by22_finish(CABACContext * const c)
++{
++ unsigned int used = c->by22.bits;
++ unsigned int bytes_used = (used / CABAC_BITS) * (CABAC_BITS / 8);
++ unsigned int bits_used = used & (CABAC_BITS == 16 ? 15 : 7);
++
++ c->bytestream += bytes_used + (CABAC_BITS / 8);
++ c->low = (((uint32_t)c->low >> (22 - CABAC_BITS + bits_used)) | 1) << bits_used;
++#if !USE_BY22_DIV
++ c->range = c->by22.range;
++#endif
++}
++
++// Peek bypass bits
++// _by22_start must be called before _by22_peek is called and _by22_flush
++// must be called afterwards to flush any used bits
++// The actual number of valid bits returned is
++// min(, CABAC_BY22_PEEK_BITS). CABAC_BY22_PEEK_BITS
++// will be at least 22 which should be long enough for any prefix or suffix
++// though probably not long enough for the worst case combination
++#ifndef get_cabac_by22_peek
++static inline uint32_t get_cabac_by22_peek(const CABACContext * const c)
++{
++#if USE_BY22_DIV
++ return ((unsigned int)c->low / (unsigned int)c->range) << 9;
++#else
++ uint32_t x = c->low & ~1U;
++ const uint32_t inv = c->range;
++
++ if (inv != 0)
++ x = (uint32_t)(((uint64_t)x * (uint64_t)inv) >> 32);
++
++ return x << 1;
++#endif
++}
++#endif
++
++// Flush bypass bits peeked by _by22_peek
++// Flush n bypass bits. n must be >= 1 to guarantee correct operation
++// val is an unmodified copy of whatever _by22_peek returned
++#ifndef get_cabac_by22_flush
++static inline void get_cabac_by22_flush(CABACContext * c, const unsigned int n, const uint32_t val)
++{
++ // Subtract the bits used & reshift up to the top of the word
++#if USE_BY22_DIV
++ const uint32_t low = (((unsigned int)c->low << n) - (((val >> (32 - n)) * (unsigned int)c->range) << 23));
++#else
++ const uint32_t low = (((uint32_t)c->low << n) - (((val >> (32 - n)) * c->by22.range) << 23));
++#endif
++
++ // and refill lower bits
++ // We will probably OR over some existing bits but that doesn't matter
++ c->by22.bits += n;
++ c->low = low | (hevc_mem_bits32(c->bytestream, c->by22.bits) >> 9);
++}
++#endif
++
++#endif // USE_BY22
++
++
+ void ff_hevc_save_states(HEVCContext *s, int ctb_addr_ts)
+ {
+ if (s->ps.pps->entropy_coding_sync_enabled_flag &&
+@@ -863,19 +1126,19 @@ int ff_hevc_cbf_luma_decode(HEVCContext *s, int trafo_depth)
+ return GET_CABAC(elem_offset[CBF_LUMA] + !trafo_depth);
+ }
+
+-static int hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx)
++static int hevc_transform_skip_flag_decode(HEVCContext *s, int c_idx_nz)
+ {
+- return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + !!c_idx);
++ return GET_CABAC(elem_offset[TRANSFORM_SKIP_FLAG] + c_idx_nz);
+ }
+
+-static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx)
++static int explicit_rdpcm_flag_decode(HEVCContext *s, int c_idx_nz)
+ {
+- return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + !!c_idx);
++ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_FLAG] + c_idx_nz);
+ }
+
+-static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx)
++static int explicit_rdpcm_dir_flag_decode(HEVCContext *s, int c_idx_nz)
+ {
+- return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + !!c_idx);
++ return GET_CABAC(elem_offset[EXPLICIT_RDPCM_DIR_FLAG] + c_idx_nz);
+ }
+
+ int ff_hevc_log2_res_scale_abs(HEVCContext *s, int idx) {
+@@ -891,14 +1154,14 @@ int ff_hevc_res_scale_sign_flag(HEVCContext *s, int idx) {
+ return GET_CABAC(elem_offset[RES_SCALE_SIGN_FLAG] + idx);
+ }
+
+-static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx,
++static av_always_inline void last_significant_coeff_xy_prefix_decode(HEVCContext *s, int c_idx_nz,
+ int log2_size, int *last_scx_prefix, int *last_scy_prefix)
+ {
+ int i = 0;
+ int max = (log2_size << 1) - 1;
+ int ctx_offset, ctx_shift;
+
+- if (!c_idx) {
++ if (!c_idx_nz) {
+ ctx_offset = 3 * (log2_size - 2) + ((log2_size - 1) >> 2);
+ ctx_shift = (log2_size + 1) >> 2;
+ } else {
+@@ -929,22 +1192,16 @@ static av_always_inline int last_significant_coeff_suffix_decode(HEVCContext *s,
+ return value;
+ }
+
+-static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx, int ctx_cg)
++static av_always_inline int significant_coeff_group_flag_decode(HEVCContext *s, int c_idx_nz, int ctx_cg)
+ {
+ int inc;
+
+- inc = FFMIN(ctx_cg, 1) + (c_idx>0 ? 2 : 0);
++ inc = (ctx_cg != 0) + (c_idx_nz << 1);
+
+ return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_GROUP_FLAG] + inc);
+ }
+-static av_always_inline int significant_coeff_flag_decode(HEVCContext *s, int x_c, int y_c,
+- int offset, const uint8_t *ctx_idx_map)
+-{
+- int inc = ctx_idx_map[(y_c << 2) + x_c] + offset;
+- return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + inc);
+-}
+
+-static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int c_idx, int offset)
++static av_always_inline int significant_coeff_flag_decode_0(HEVCContext *s, int offset)
+ {
+ return GET_CABAC(elem_offset[SIGNIFICANT_COEFF_FLAG] + offset);
+ }
+@@ -966,65 +1223,305 @@ static av_always_inline int coeff_abs_level_greater2_flag_decode(HEVCContext *s,
+ return GET_CABAC(elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] + inc);
+ }
+
+-static av_always_inline int coeff_abs_level_remaining_decode(HEVCContext *s, int rc_rice_param)
++
++#if !USE_BY22
++#define coeff_abs_level_remaining_decode_bypass(s,r) coeff_abs_level_remaining_decode(s, r)
++#endif
++
++
++#ifndef coeff_abs_level_remaining_decode_bypass
++static int coeff_abs_level_remaining_decode_bypass(HEVCContext * const s, const unsigned int rice_param)
++{
++ CABACContext * const c = &s->HEVClc->cc;
++ uint32_t y;
++ unsigned int prefix;
++ unsigned int last_coeff_abs_level_remaining;
++ unsigned int n;
++
++ y = get_cabac_by22_peek(c);
++ prefix = hevc_clz32(~y);
++ // y << prefix will always have top bit 0
++
++ if (prefix < 3) {
++ const unsigned int suffix = (y << prefix) >> (31 - rice_param);
++ last_coeff_abs_level_remaining = (prefix << rice_param) + suffix;
++ n = prefix + 1 + rice_param;
++ }
++ else if (prefix * 2 + rice_param <= CABAC_BY22_PEEK_BITS + 2)
++ {
++ const uint32_t suffix = ((y << prefix) | 0x80000000) >> (34 - (prefix + rice_param));
++
++ last_coeff_abs_level_remaining = (2 << rice_param) + suffix;
++ n = prefix * 2 + rice_param - 2;
++ }
++ else {
++ unsigned int suffix;
++
++ get_cabac_by22_flush(c, prefix, y);
++ y = get_cabac_by22_peek(c);
++
++ suffix = (y | 0x80000000) >> (34 - (prefix + rice_param));
++ last_coeff_abs_level_remaining = (2 << rice_param) + suffix;
++ n = prefix + rice_param - 2;
++ }
++
++ get_cabac_by22_flush(c, n, y);
++
++ return last_coeff_abs_level_remaining;
++}
++#endif
++
++static int coeff_abs_level_remaining_decode(HEVCContext * const s, int rc_rice_param)
+ {
++ CABACContext * const c = &s->HEVClc->cc;
+ int prefix = 0;
+ int suffix = 0;
+ int last_coeff_abs_level_remaining;
+ int i;
+
+- while (prefix < CABAC_MAX_BIN && get_cabac_bypass(&s->HEVClc->cc))
++ while (prefix < CABAC_MAX_BIN && get_cabac_bypass(c))
+ prefix++;
+ if (prefix == CABAC_MAX_BIN) {
+ av_log(s->avctx, AV_LOG_ERROR, "CABAC_MAX_BIN : %d\n", prefix);
+ return 0;
+ }
++
+ if (prefix < 3) {
+ for (i = 0; i < rc_rice_param; i++)
+- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc);
++ suffix = (suffix << 1) | get_cabac_bypass(c);
+ last_coeff_abs_level_remaining = (prefix << rc_rice_param) + suffix;
+ } else {
+ int prefix_minus3 = prefix - 3;
+ for (i = 0; i < prefix_minus3 + rc_rice_param; i++)
+- suffix = (suffix << 1) | get_cabac_bypass(&s->HEVClc->cc);
++ suffix = (suffix << 1) | get_cabac_bypass(c);
+ last_coeff_abs_level_remaining = (((1 << prefix_minus3) + 3 - 1)
+ << rc_rice_param) + suffix;
+ }
++
+ return last_coeff_abs_level_remaining;
+ }
+
+-static av_always_inline int coeff_sign_flag_decode(HEVCContext *s, uint8_t nb)
++#if !USE_BY22
++#define coeff_sign_flag_decode_bypass coeff_sign_flag_decode
++static inline uint32_t coeff_sign_flag_decode(HEVCContext * const s, const unsigned int nb)
+ {
+- int i;
+- int ret = 0;
++ CABACContext * const c = &s->HEVClc->cc;
++ unsigned int i;
++ uint32_t ret = 0;
+
+ for (i = 0; i < nb; i++)
+- ret = (ret << 1) | get_cabac_bypass(&s->HEVClc->cc);
+- return ret;
++ ret = (ret << 1) | get_cabac_bypass(c);
++
++ return ret << (32 - nb);
+ }
++#endif
++
++#ifndef coeff_sign_flag_decode_bypass
++static inline uint32_t coeff_sign_flag_decode_bypass(HEVCContext * const s, const unsigned int nb)
++{
++ CABACContext * const c = &s->HEVClc->cc;
++ uint32_t y;
++ y = get_cabac_by22_peek(c);
++ get_cabac_by22_flush(c, nb, y);
++ return y & ~(0xffffffffU >> nb);
++}
++#endif
++
++
++#ifndef get_cabac_greater1_bits
++static inline unsigned int get_cabac_greater1_bits(CABACContext * const c, const unsigned int n,
++ uint8_t * const state0)
++{
++ unsigned int i;
++ unsigned int rv = 0;
++ for (i = 0; i != n; ++i) {
++ const unsigned int idx = rv != 0 ? 0 : i < 3 ? i + 1 : 3;
++ const unsigned int b = get_cabac(c, state0 + idx);
++ rv = (rv << 1) | b;
++ }
++ return rv;
++}
++#endif
++
++
++// N.B. levels returned are the values assuming coeff_abs_level_remaining
++// is uncoded, so 1 must be added if it is coded. sum_abs also reflects
++// this version of events.
++static inline uint32_t get_greaterx_bits(HEVCContext * const s, const unsigned int n_end, int * const levels,
++ int * const pprev_subset_coded, int * const psum,
++ const unsigned int idx0_gt1, const unsigned int idx_gt2)
++{
++ CABACContext * const c = &s->HEVClc->cc;
++ uint8_t * const state0 = s->HEVClc->cabac_state + idx0_gt1;
++ uint8_t * const state_gt2 = s->HEVClc->cabac_state + idx_gt2;
++ unsigned int rv;
++ unsigned int i;
++ const unsigned int n = FFMIN(n_end, 8);
++
++ // Really this is i != n but the simple unconditional loop is cheaper
++ // and faster
++ for (i = 0; i != 8; ++i)
++ levels[i] = 1;
++
++ rv = get_cabac_greater1_bits(c, n, state0);
++
++ *pprev_subset_coded = 0;
++ *psum = n;
++
++ rv <<= (32 - n);
++ if (rv != 0)
++ {
++ *pprev_subset_coded = 1;
++ *psum = n + 1;
++ i = hevc_clz32(rv);
++ levels[i] = 2;
++ if (get_cabac(c, state_gt2) == 0)
++ {
++ // Unset first coded bit
++ rv &= ~(0x80000000U >> i);
++ }
++ }
++
++ if (n_end > 8) {
++ const unsigned int g8 = n_end - 8;
++ rv |= ((1 << g8) - 1) << (24 - g8);
++ for (i = 0; i != g8; ++i) {
++ levels[i + 8] = 0;
++ }
++ }
++
++ return rv;
++}
++
++// extended_precision_processing_flag must be false given we are
++// putting the result into a 16-bit array
++// So trans_coeff_level must fit in 16 bits too (7.4.9.1 definition of coeff_abs_level_remaining)
++// scale_m is uint8_t
++//
++// scale is [40 - 72] << [0..12] based on qp- worst case is (45 << 12)
++// or it can be 2 (if we have transquant_bypass)
++// shift is set to one less than we really want but would normally be
++// s->ps.sps->bit_depth (max 16, min 8) + log2_trafo_size (max 5, min 2?) - 5 = max 16 min 5?
++// however the scale shift is substracted from shift to a min 0 so scale_m worst = 45 << 6
++// This can still theoretically lead to overflow but the coding would have to be very odd (& inefficient)
++// to achieve it
++
++#ifndef trans_scale_sat
++static inline int trans_scale_sat(const int level, const unsigned int scale, const unsigned int scale_m, const unsigned int shift)
++{
++ return av_clip_int16((((level * (int)(scale * scale_m)) >> shift) + 1) >> 1);
++}
++#endif
++
++
++#ifndef update_rice
++static inline void update_rice(uint8_t * const stat_coeff,
++ const unsigned int last_coeff_abs_level_remaining,
++ const unsigned int c_rice_param)
++{
++ const unsigned int x = (last_coeff_abs_level_remaining << 1) >> c_rice_param;
++ if (x >= 6)
++ (*stat_coeff)++;
++ else if (x == 0 && *stat_coeff > 0)
++ (*stat_coeff)--;
++}
++#endif
++
++
++// n must be > 0 on entry
++#ifndef get_cabac_sig_coeff_flag_idxs
++static inline uint8_t * get_cabac_sig_coeff_flag_idxs(CABACContext * const c, uint8_t * const state0,
++ unsigned int n,
++ const uint8_t const * ctx_map,
++ uint8_t * p)
++{
++ do {
++ if (get_cabac(c, state0 + ctx_map[n]))
++ *p++ = n;
++ } while (--n != 0);
++ return p;
++}
++#endif
++
++
++static int get_sig_coeff_flag_idxs(CABACContext * const c, uint8_t * const state0,
++ unsigned int n,
++ const uint8_t const * ctx_map,
++ uint8_t * const flag_idx)
++{
++ int rv;
++
++ rv = get_cabac_sig_coeff_flag_idxs(c, state0, n, ctx_map, flag_idx) - flag_idx;
++
++ return rv;
++}
++
++#define H4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\
++ x0, x1, x2, x3,\
++ x4, x5, x6, x7,\
++ x8, x9, x10, x11,\
++ x12, x13, x14, x15}
++
++#define V4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\
++ x0, x4, x8, x12,\
++ x1, x5, x9, x13,\
++ x2, x6, x10, x14,\
++ x3, x7, x11, x15}
++
++#define D4x4(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15) {\
++ x0, x4, x1, x8,\
++ x5, x2, x12, x9,\
++ x6, x3, x13, x10,\
++ x7, x14, x11, x15}
++
++
++static inline int next_subset(HEVCContext * const s, int i, const int c_idx_nz,
++ uint8_t * const significant_coeff_group_flag,
++ const uint8_t * const scan_x_cg, const uint8_t * const scan_y_cg,
++ int * const pPrev_sig)
++{
++ while (--i >= 0) {
++ unsigned int x_cg = scan_x_cg[i];
++ unsigned int y_cg = scan_y_cg[i];
++
++ // For the flag decode we only care about Z/NZ but
++ // we use the full Right + Down * 2 when calculating
++ // significant coeff flags so we obtain it here
++ //.
++ // The group flag array is one longer than it needs to
++ // be so we don't need to check for y_cg limits
++ unsigned int prev_sig = ((significant_coeff_group_flag[y_cg] >> (x_cg + 1)) & 1) |
++ (((significant_coeff_group_flag[y_cg + 1] >> x_cg) & 1) << 1);
++
++ if (i == 0 ||
++ significant_coeff_group_flag_decode(s, c_idx_nz, prev_sig))
++ {
++ significant_coeff_group_flag[y_cg] |= (1 << x_cg);
++ *pPrev_sig = prev_sig;
++ break;
++ }
++ }
++
++ return i;
++}
++
+
+ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ int log2_trafo_size, enum ScanType scan_idx,
+ int c_idx)
+ {
+-#define GET_COORD(offset, n) \
+- do { \
+- x_c = (x_cg << 2) + scan_x_off[n]; \
+- y_c = (y_cg << 2) + scan_y_off[n]; \
+- } while (0)
+- HEVCLocalContext *lc = s->HEVClc;
+- int transform_skip_flag = 0;
++ HEVCLocalContext * const lc = s->HEVClc;
++ int trans_skip_or_bypass = lc->cu.cu_transquant_bypass_flag;
+
+ int last_significant_coeff_x, last_significant_coeff_y;
+- int last_scan_pos;
+- int n_end;
+ int num_coeff = 0;
+- int greater1_ctx = 1;
++ int prev_subset_coded = 0;
+
+ int num_last_subset;
+ int x_cg_last_sig, y_cg_last_sig;
+
+- const uint8_t *scan_x_cg, *scan_y_cg, *scan_x_off, *scan_y_off;
++ const uint8_t *scan_x_cg, *scan_y_cg;
++ const xy_off_t * scan_xy_off;
+
+ ptrdiff_t stride = s->frame->linesize[c_idx];
+ int hshift = s->ps.sps->hshift[c_idx];
+@@ -1032,21 +1529,28 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ uint8_t *dst = &s->frame->data[c_idx][(y0 >> vshift) * stride +
+ ((x0 >> hshift) << s->ps.sps->pixel_shift)];
+ #ifdef RPI
+- int use_vpu = s->enable_rpi && !lc->cu.cu_transquant_bypass_flag && !transform_skip_flag && !lc->tu.cross_pf && log2_trafo_size>=4;
++ //***** transform_skip_flag decoded later!
++ int use_vpu = s->enable_rpi && !lc->cu.cu_transquant_bypass_flag /* && !transform_skip_flag*/ && !lc->tu.cross_pf && log2_trafo_size>=4;
+ #endif
+ int16_t *coeffs = (int16_t*)(c_idx ? lc->edge_emu_buffer2 : lc->edge_emu_buffer);
+- uint8_t significant_coeff_group_flag[8][8] = {{0}};
++ uint8_t significant_coeff_group_flag[9] = {0}; // Allow 1 final byte that is always zero
+ int explicit_rdpcm_flag = 0;
+ int explicit_rdpcm_dir_flag;
+
+ int trafo_size = 1 << log2_trafo_size;
+ int i;
+- int qp,shift,add,scale,scale_m;
+- const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 };
++ int qp,shift,scale;
++ static const uint8_t level_scale[] = { 40, 45, 51, 57, 64, 72 };
+ const uint8_t *scale_matrix = NULL;
+ uint8_t dc_scale;
+ int pred_mode_intra = (c_idx == 0) ? lc->tu.intra_pred_mode :
+ lc->tu.intra_pred_mode_c;
++
++ int prev_sig = 0;
++ const int c_idx_nz = (c_idx != 0);
++
++ int may_hide_sign;
++
+ #ifdef RPI
+ if (s->enable_rpi) {
+ int n = trafo_size * trafo_size;
+@@ -1078,7 +1582,7 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+
+ // Derive QP for dequant
+ if (!lc->cu.cu_transquant_bypass_flag) {
+- static const int qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 };
++ static const uint8_t qp_c[] = { 29, 30, 31, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37 };
+ static const uint8_t rem6[51 + 4 * 6 + 1] = {
+ 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2,
+ 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5, 0, 1, 2, 3, 4, 5,
+@@ -1094,9 +1598,19 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ };
+ int qp_y = lc->qp_y;
+
++ may_hide_sign = s->ps.pps->sign_data_hiding_flag;
++
+ if (s->ps.pps->transform_skip_enabled_flag &&
+ log2_trafo_size <= s->ps.pps->log2_max_transform_skip_block_size) {
+- transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx);
++ int transform_skip_flag = hevc_transform_skip_flag_decode(s, c_idx_nz);
++ if (transform_skip_flag) {
++ trans_skip_or_bypass = 1;
++ if (lc->cu.pred_mode == MODE_INTRA &&
++ s->ps.sps->implicit_rdpcm_enabled_flag &&
++ (pred_mode_intra == 10 || pred_mode_intra == 26)) {
++ may_hide_sign = 0;
++ }
++ }
+ }
+
+ if (c_idx == 0) {
+@@ -1129,39 +1643,73 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ qp += s->ps.sps->qp_bd_offset;
+ }
+
+- shift = s->ps.sps->bit_depth + log2_trafo_size - 5;
+- add = 1 << (shift-1);
+- scale = level_scale[rem6[qp]] << (div6[qp]);
+- scale_m = 16; // default when no custom scaling lists.
+- dc_scale = 16;
++ // Shift is set to one less than will actually occur as the scale
++ // and saturate step adds 1 and then shifts right again
++ shift = s->ps.sps->bit_depth + log2_trafo_size - 6;
++ scale = level_scale[rem6[qp]];
++ if (div6[qp] >= shift) {
++ scale <<= (div6[qp] - shift);
++ shift = 0;
++ } else {
++ shift -= div6[qp];
++ }
+
+- if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
++ if (s->ps.sps->scaling_list_enable_flag && !(trans_skip_or_bypass && log2_trafo_size > 2)) {
+ const ScalingList *sl = s->ps.pps->scaling_list_data_present_flag ?
+- &s->ps.pps->scaling_list : &s->ps.sps->scaling_list;
++ &s->ps.pps->scaling_list : &s->ps.sps->scaling_list;
+ int matrix_id = lc->cu.pred_mode != MODE_INTRA;
+
+ matrix_id = 3 * matrix_id + c_idx;
+
+ scale_matrix = sl->sl[log2_trafo_size - 2][matrix_id];
++ dc_scale = scale_matrix[0];
+ if (log2_trafo_size >= 4)
+ dc_scale = sl->sl_dc[log2_trafo_size - 4][matrix_id];
+ }
++ else
++ {
++ static const uint8_t sixteen_scale[64] = {
++ 16, 16, 16, 16, 16, 16, 16, 16,
++ 16, 16, 16, 16, 16, 16, 16, 16,
++ 16, 16, 16, 16, 16, 16, 16, 16,
++ 16, 16, 16, 16, 16, 16, 16, 16,
++ 16, 16, 16, 16, 16, 16, 16, 16,
++ 16, 16, 16, 16, 16, 16, 16, 16,
++ 16, 16, 16, 16, 16, 16, 16, 16,
++ 16, 16, 16, 16, 16, 16, 16, 16
++ };
++ scale_matrix = sixteen_scale;
++ dc_scale = 16;
++ }
+ } else {
++ static const uint8_t unit_scale[64] = {
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ 1, 1, 1, 1, 1, 1, 1, 1,
++ };
++ scale_matrix = unit_scale;
+ shift = 0;
+- add = 0;
+- scale = 0;
+- dc_scale = 0;
++ scale = 2; // We will shift right to kill this
++ dc_scale = 1;
++
++ may_hide_sign = 0;
+ }
+
+ if (lc->cu.pred_mode == MODE_INTER && s->ps.sps->explicit_rdpcm_enabled_flag &&
+- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
+- explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx);
++ trans_skip_or_bypass) {
++ explicit_rdpcm_flag = explicit_rdpcm_flag_decode(s, c_idx_nz);
+ if (explicit_rdpcm_flag) {
+- explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx);
++ may_hide_sign = 0;
++ explicit_rdpcm_dir_flag = explicit_rdpcm_dir_flag_decode(s, c_idx_nz);
+ }
+ }
+
+- last_significant_coeff_xy_prefix_decode(s, c_idx, log2_trafo_size,
++ last_significant_coeff_xy_prefix_decode(s, c_idx_nz, log2_trafo_size,
+ &last_significant_coeff_x, &last_significant_coeff_y);
+
+ if (last_significant_coeff_x > 3) {
+@@ -1189,119 +1737,113 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ int last_x_c = last_significant_coeff_x & 3;
+ int last_y_c = last_significant_coeff_y & 3;
+
+- scan_x_off = ff_hevc_diag_scan4x4_x;
+- scan_y_off = ff_hevc_diag_scan4x4_y;
+ num_coeff = diag_scan4x4_inv[last_y_c][last_x_c];
+- if (trafo_size == 4) {
++
++ switch (log2_trafo_size) {
++ case 2:
+ scan_x_cg = scan_1x1;
+ scan_y_cg = scan_1x1;
+- } else if (trafo_size == 8) {
++ break;
++ case 3:
+ num_coeff += diag_scan2x2_inv[y_cg_last_sig][x_cg_last_sig] << 4;
+ scan_x_cg = diag_scan2x2_x;
+ scan_y_cg = diag_scan2x2_y;
+- } else if (trafo_size == 16) {
++ break;
++ case 4:
+ num_coeff += diag_scan4x4_inv[y_cg_last_sig][x_cg_last_sig] << 4;
+ scan_x_cg = ff_hevc_diag_scan4x4_x;
+ scan_y_cg = ff_hevc_diag_scan4x4_y;
+- } else { // trafo_size == 32
++ break;
++ case 5:
++ default:
+ num_coeff += diag_scan8x8_inv[y_cg_last_sig][x_cg_last_sig] << 4;
+ scan_x_cg = ff_hevc_diag_scan8x8_x;
+ scan_y_cg = ff_hevc_diag_scan8x8_y;
++ break;
+ }
+ break;
+ }
+ case SCAN_HORIZ:
+ scan_x_cg = horiz_scan2x2_x;
+ scan_y_cg = horiz_scan2x2_y;
+- scan_x_off = horiz_scan4x4_x;
+- scan_y_off = horiz_scan4x4_y;
+ num_coeff = horiz_scan8x8_inv[last_significant_coeff_y][last_significant_coeff_x];
+ break;
+ default: //SCAN_VERT
+ scan_x_cg = horiz_scan2x2_y;
+ scan_y_cg = horiz_scan2x2_x;
+- scan_x_off = horiz_scan4x4_y;
+- scan_y_off = horiz_scan4x4_x;
+ num_coeff = horiz_scan8x8_inv[last_significant_coeff_x][last_significant_coeff_y];
+ break;
+ }
+ num_coeff++;
+ num_last_subset = (num_coeff - 1) >> 4;
+
+- for (i = num_last_subset; i >= 0; i--) {
+- int n, m;
+- int x_cg, y_cg, x_c, y_c, pos;
+- int implicit_non_zero_coeff = 0;
+- int64_t trans_coeff_level;
+- int prev_sig = 0;
+- int offset = i << 4;
+- int rice_init = 0;
+-
+- uint8_t significant_coeff_flag_idx[16];
+- uint8_t nb_significant_coeff_flag = 0;
++ significant_coeff_group_flag[y_cg_last_sig] = 1 << x_cg_last_sig; // 1st subset always significant
+
+- x_cg = scan_x_cg[i];
+- y_cg = scan_y_cg[i];
++ scan_xy_off = off_xys[scan_idx][log2_trafo_size - 2];
+
+- if ((i < num_last_subset) && (i > 0)) {
+- int ctx_cg = 0;
+- if (x_cg < (1 << (log2_trafo_size - 2)) - 1)
+- ctx_cg += significant_coeff_group_flag[x_cg + 1][y_cg];
+- if (y_cg < (1 << (log2_trafo_size - 2)) - 1)
+- ctx_cg += significant_coeff_group_flag[x_cg][y_cg + 1];
+-
+- significant_coeff_group_flag[x_cg][y_cg] =
+- significant_coeff_group_flag_decode(s, c_idx, ctx_cg);
+- implicit_non_zero_coeff = 1;
+- } else {
+- significant_coeff_group_flag[x_cg][y_cg] =
+- ((x_cg == x_cg_last_sig && y_cg == y_cg_last_sig) ||
+- (x_cg == 0 && y_cg == 0));
+- }
++ i = num_last_subset;
++ do {
++ int implicit_non_zero_coeff = 0;
++ int n_end;
+
+- last_scan_pos = num_coeff - offset - 1;
++ uint8_t significant_coeff_flag_idx[16];
++ unsigned int nb_significant_coeff_flag = 0;
+
+ if (i == num_last_subset) {
++ // First time through
++ int last_scan_pos = num_coeff - (i << 4) - 1;
+ n_end = last_scan_pos - 1;
+ significant_coeff_flag_idx[0] = last_scan_pos;
+ nb_significant_coeff_flag = 1;
+ } else {
+ n_end = 15;
++ implicit_non_zero_coeff = (i != 0);
+ }
+
+- if (x_cg < ((1 << log2_trafo_size) - 1) >> 2)
+- prev_sig = !!significant_coeff_group_flag[x_cg + 1][y_cg];
+- if (y_cg < ((1 << log2_trafo_size) - 1) >> 2)
+- prev_sig += (!!significant_coeff_group_flag[x_cg][y_cg + 1] << 1);
+-
+- if (significant_coeff_group_flag[x_cg][y_cg] && n_end >= 0) {
+- static const uint8_t ctx_idx_map[] = {
+- 0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8, // log2_trafo_size == 2
+- 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 0
+- 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, // prev_sig == 1
+- 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, // prev_sig == 2
+- 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 // default
++ if (n_end >= 0) {
++ static const uint8_t ctx_idx_maps_ts2[3][16] = {
++ D4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8), // log2_trafo_size == 2
++ H4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8), // log2_trafo_size == 2
++ V4x4(0, 1, 4, 5, 2, 3, 4, 5, 6, 6, 8, 8, 7, 7, 8, 8) // log2_trafo_size == 2
++ };
++ static const uint8_t ctx_idx_maps[3][4][16] = {
++ {
++ D4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0
++ D4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1
++ D4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2
++ D4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default
++ },
++ {
++ H4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0
++ H4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1
++ H4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2
++ H4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default
++ },
++ {
++ V4x4(1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 0
++ V4x4(2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0), // prev_sig == 1
++ V4x4(2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0, 2, 1, 0, 0), // prev_sig == 2
++ V4x4(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2) // prev_sig == 3, default
++ }
+ };
+ const uint8_t *ctx_idx_map_p;
+ int scf_offset = 0;
+- if (s->ps.sps->transform_skip_context_enabled_flag &&
+- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
+- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[4 * 16];
+- if (c_idx == 0) {
+- scf_offset = 40;
+- } else {
+- scf_offset = 14 + 27;
+- }
++
++ if (s->ps.sps->transform_skip_context_enabled_flag && trans_skip_or_bypass) {
++ ctx_idx_map_p = ctx_idx_maps[0][3];
++ scf_offset = 40 + c_idx_nz;
+ } else {
+- if (c_idx != 0)
++ if (c_idx_nz != 0)
+ scf_offset = 27;
++
+ if (log2_trafo_size == 2) {
+- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[0];
++ ctx_idx_map_p = ctx_idx_maps_ts2[scan_idx];
+ } else {
+- ctx_idx_map_p = (uint8_t*) &ctx_idx_map[(prev_sig + 1) << 4];
+- if (c_idx == 0) {
+- if ((x_cg > 0 || y_cg > 0))
++ ctx_idx_map_p = ctx_idx_maps[scan_idx][prev_sig];
++ if (!c_idx_nz) {
++ if (i != 0)
+ scf_offset += 3;
++
+ if (log2_trafo_size == 3) {
+ scf_offset += (scan_idx == SCAN_DIAG) ? 9 : 15;
+ } else {
+@@ -1315,34 +1857,30 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ }
+ }
+ }
+- for (n = n_end; n > 0; n--) {
+- x_c = scan_x_off[n];
+- y_c = scan_y_off[n];
+- if (significant_coeff_flag_decode(s, x_c, y_c, scf_offset, ctx_idx_map_p)) {
+- significant_coeff_flag_idx[nb_significant_coeff_flag] = n;
+- nb_significant_coeff_flag++;
++
++ if (n_end > 0) {
++ int cnt = get_sig_coeff_flag_idxs(&s->HEVClc->cc,
++ s->HEVClc->cabac_state + elem_offset[SIGNIFICANT_COEFF_FLAG] + scf_offset,
++ n_end, ctx_idx_map_p,
++ significant_coeff_flag_idx + nb_significant_coeff_flag);
++
++ nb_significant_coeff_flag += cnt;
++ if (cnt != 0) {
+ implicit_non_zero_coeff = 0;
+ }
+ }
++
+ if (implicit_non_zero_coeff == 0) {
+- if (s->ps.sps->transform_skip_context_enabled_flag &&
+- (transform_skip_flag || lc->cu.cu_transquant_bypass_flag)) {
+- if (c_idx == 0) {
+- scf_offset = 42;
+- } else {
+- scf_offset = 16 + 27;
+- }
++ if (s->ps.sps->transform_skip_context_enabled_flag && trans_skip_or_bypass) {
++ scf_offset = 42 + c_idx_nz;
+ } else {
+ if (i == 0) {
+- if (c_idx == 0)
+- scf_offset = 0;
+- else
+- scf_offset = 27;
++ scf_offset = c_idx_nz ? 27 : 0;
+ } else {
+ scf_offset = 2 + scf_offset;
+ }
+ }
+- if (significant_coeff_flag_decode_0(s, c_idx, scf_offset) == 1) {
++ if (significant_coeff_flag_decode_0(s, scf_offset) == 1) {
+ significant_coeff_flag_idx[nb_significant_coeff_flag] = 0;
+ nb_significant_coeff_flag++;
+ }
+@@ -1352,141 +1890,185 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ }
+ }
+
+- n_end = nb_significant_coeff_flag;
+-
++ if (nb_significant_coeff_flag != 0) {
++ const unsigned int gt1_idx_delta = (c_idx_nz << 2) |
++ ((i != 0 && !c_idx_nz) ? 2 : 0) |
++ prev_subset_coded;
++ const unsigned int idx0_gt1 = elem_offset[COEFF_ABS_LEVEL_GREATER1_FLAG] +
++ (gt1_idx_delta << 2);
++ const unsigned int idx_gt2 = elem_offset[COEFF_ABS_LEVEL_GREATER2_FLAG] +
++ gt1_idx_delta;
++
++ const unsigned int x_cg = scan_x_cg[i];
++ const unsigned int y_cg = scan_y_cg[i];
++ int16_t * const blk_coeffs = coeffs +
++ ((x_cg + (y_cg << log2_trafo_size)) << 2);
++ // This calculation is 'wrong' for log2_traffo_size == 2
++ // but that doesn't mattor as in this case x_cg & y_cg
++ // are always 0 so result is correct (0) anyway
++ const uint8_t * const blk_scale = scale_matrix +
++ (((x_cg + (y_cg << 3)) << (5 - log2_trafo_size)));
++
++ // * THe following code block doesn't deal with these flags:
++ // (nor did the one it replaces)
++ //
++ // cabac_bypass_alignment_enabled_flag
++ // This should be easy but I can't find a test case
++ // extended_precision_processing_flag
++ // This can extend the required precision past 16bits
++ // so is probably tricky - also no example found yet
++
++#if USE_N_END_1
++ if (nb_significant_coeff_flag == 1) {
++ // There is a small gain to be had from special casing the single
++ // transform coefficient case. The reduction in complexity
++ // makes up for the code duplicatioon.
++
++ int trans_coeff_level = 1;
++ int coeff_sign_flag;
++ int coded_val = 0;
++
++ // initialize first elem of coeff_bas_level_greater1_flag
++ prev_subset_coded = 0;
++
++ if (get_cabac(&s->HEVClc->cc, s->HEVClc->cabac_state + idx0_gt1 + 1)) {
++ trans_coeff_level = 2;
++ prev_subset_coded = 1;
++ coded_val = get_cabac(&s->HEVClc->cc, s->HEVClc->cabac_state + idx_gt2);
++ }
+
+- if (n_end) {
+- int first_nz_pos_in_cg;
+- int last_nz_pos_in_cg;
+- int c_rice_param = 0;
+- int first_greater1_coeff_idx = -1;
+- uint8_t coeff_abs_level_greater1_flag[8];
+- uint16_t coeff_sign_flag;
+- int sum_abs = 0;
+- int sign_hidden;
+- int sb_type;
++ // Probably not worth the overhead of starting by22 for just one value
++ coeff_sign_flag = get_cabac_bypass(&s->HEVClc->cc);
+
++ if (coded_val)
++ {
++ if (!s->ps.sps->persistent_rice_adaptation_enabled_flag) {
++ trans_coeff_level = 3 + coeff_abs_level_remaining_decode(s, 0);
++ } else {
++ uint8_t * const stat_coeff =
++ lc->stat_coeff + trans_skip_or_bypass + 2 - ((c_idx_nz) << 1);
++ const unsigned int c_rice_param = *stat_coeff >> 2;
++ const int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
+
+- // initialize first elem of coeff_bas_level_greater1_flag
+- int ctx_set = (i > 0 && c_idx == 0) ? 2 : 0;
++ trans_coeff_level = 3 + last_coeff_abs_level_remaining;
++ update_rice(stat_coeff, last_coeff_abs_level_remaining, c_rice_param);
++ }
++ }
+
+- if (s->ps.sps->persistent_rice_adaptation_enabled_flag) {
+- if (!transform_skip_flag && !lc->cu.cu_transquant_bypass_flag)
+- sb_type = 2 * (c_idx == 0 ? 1 : 0);
+- else
+- sb_type = 2 * (c_idx == 0 ? 1 : 0) + 1;
+- c_rice_param = lc->stat_coeff[sb_type] / 4;
+- }
++ {
++ const xy_off_t * const xy_off = scan_xy_off + significant_coeff_flag_idx[0];
++ const int k = (int32_t)(coeff_sign_flag << 31) >> 31;
++ const unsigned int scale_m = blk_scale[xy_off->scale];
+
+- if (!(i == num_last_subset) && greater1_ctx == 0)
+- ctx_set++;
+- greater1_ctx = 1;
+- last_nz_pos_in_cg = significant_coeff_flag_idx[0];
+-
+- for (m = 0; m < (n_end > 8 ? 8 : n_end); m++) {
+- int inc = (ctx_set << 2) + greater1_ctx;
+- coeff_abs_level_greater1_flag[m] =
+- coeff_abs_level_greater1_flag_decode(s, c_idx, inc);
+- if (coeff_abs_level_greater1_flag[m]) {
+- greater1_ctx = 0;
+- if (first_greater1_coeff_idx == -1)
+- first_greater1_coeff_idx = m;
+- } else if (greater1_ctx > 0 && greater1_ctx < 3) {
+- greater1_ctx++;
++ blk_coeffs[xy_off->coeff] = trans_scale_sat(
++ (trans_coeff_level ^ k) - k, // Apply sign
++ scale,
++ i == 0 && xy_off->coeff == 0 ? dc_scale : scale_m,
++ shift);
+ }
+ }
+- first_nz_pos_in_cg = significant_coeff_flag_idx[n_end - 1];
+-
+- if (lc->cu.cu_transquant_bypass_flag ||
+- (lc->cu.pred_mode == MODE_INTRA &&
+- s->ps.sps->implicit_rdpcm_enabled_flag && transform_skip_flag &&
+- (pred_mode_intra == 10 || pred_mode_intra == 26 )) ||
+- explicit_rdpcm_flag)
+- sign_hidden = 0;
+ else
+- sign_hidden = (last_nz_pos_in_cg - first_nz_pos_in_cg >= 4);
++#endif
++ {
++ int sign_hidden = may_hide_sign;
++ int levels[16]; // Should be able to get away with int16_t but that fails some tests
++ uint32_t coeff_sign_flags;
++ uint32_t coded_vals = 0;
++ // Sum(abs(level[]))
++ // In fact we only need the bottom bit and in some future
++ // version that may be all we calculate
++ unsigned int sum_abs;
++
++ coded_vals = get_greaterx_bits(s, nb_significant_coeff_flag, levels,
++ &prev_subset_coded, &sum_abs, idx0_gt1, idx_gt2);
++
++ if (significant_coeff_flag_idx[0] - significant_coeff_flag_idx[nb_significant_coeff_flag - 1] <= 3)
++ sign_hidden = 0;
++
++ // -- Start bypass block
++
++ bypass_start(s);
++
++ coeff_sign_flags = coeff_sign_flag_decode_bypass(s, nb_significant_coeff_flag - sign_hidden);
++
++ if (coded_vals != 0)
++ {
++ const int rice_adaptation_enabled = s->ps.sps->persistent_rice_adaptation_enabled_flag;
++ uint8_t * stat_coeff = !rice_adaptation_enabled ? NULL :
++ lc->stat_coeff + trans_skip_or_bypass + 2 - ((c_idx_nz) << 1);
++ int c_rice_param = !rice_adaptation_enabled ? 0 : *stat_coeff >> 2;
++ int * level = levels - 1;
++
++ do {
++ {
++ const unsigned int z = hevc_clz32(coded_vals) + 1;
++ level += z;
++ coded_vals <<= z;
++ }
+
+- if (first_greater1_coeff_idx != -1) {
+- coeff_abs_level_greater1_flag[first_greater1_coeff_idx] += coeff_abs_level_greater2_flag_decode(s, c_idx, ctx_set);
+- }
+- if (!s->ps.pps->sign_data_hiding_flag || !sign_hidden ) {
+- coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag) << (16 - nb_significant_coeff_flag);
+- } else {
+- coeff_sign_flag = coeff_sign_flag_decode(s, nb_significant_coeff_flag - 1) << (16 - (nb_significant_coeff_flag - 1));
+- }
++ {
++ const int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode_bypass(s, c_rice_param);
++ const int trans_coeff_level = *level + last_coeff_abs_level_remaining + 1;
++
++ sum_abs += last_coeff_abs_level_remaining + 1;
++ *level = trans_coeff_level;
+
+- for (m = 0; m < n_end; m++) {
+- n = significant_coeff_flag_idx[m];
+- GET_COORD(offset, n);
+- if (m < 8) {
+- trans_coeff_level = 1 + coeff_abs_level_greater1_flag[m];
+- if (trans_coeff_level == ((m == first_greater1_coeff_idx) ? 3 : 2)) {
+- int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
+-
+- trans_coeff_level += last_coeff_abs_level_remaining;
+- if (trans_coeff_level > (3 << c_rice_param))
+- c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
+- if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
+- int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
+- if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
+- lc->stat_coeff[sb_type]++;
+- else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
+- if (lc->stat_coeff[sb_type] > 0)
+- lc->stat_coeff[sb_type]--;
+- rice_init = 1;
++ if (stat_coeff != NULL)
++ update_rice(stat_coeff, last_coeff_abs_level_remaining, c_rice_param);
++ stat_coeff = NULL;
++
++ if (trans_coeff_level > (3 << c_rice_param) &&
++ (c_rice_param < 4 || rice_adaptation_enabled))
++ ++c_rice_param;
+ }
+- }
+- } else {
+- int last_coeff_abs_level_remaining = coeff_abs_level_remaining_decode(s, c_rice_param);
+-
+- trans_coeff_level = 1 + last_coeff_abs_level_remaining;
+- if (trans_coeff_level > (3 << c_rice_param))
+- c_rice_param = s->ps.sps->persistent_rice_adaptation_enabled_flag ? c_rice_param + 1 : FFMIN(c_rice_param + 1, 4);
+- if (s->ps.sps->persistent_rice_adaptation_enabled_flag && !rice_init) {
+- int c_rice_p_init = lc->stat_coeff[sb_type] / 4;
+- if (last_coeff_abs_level_remaining >= (3 << c_rice_p_init))
+- lc->stat_coeff[sb_type]++;
+- else if (2 * last_coeff_abs_level_remaining < (1 << c_rice_p_init))
+- if (lc->stat_coeff[sb_type] > 0)
+- lc->stat_coeff[sb_type]--;
+- rice_init = 1;
+- }
++ } while (coded_vals != 0);
+ }
+- if (s->ps.pps->sign_data_hiding_flag && sign_hidden) {
+- sum_abs += trans_coeff_level;
+- if (n == first_nz_pos_in_cg && (sum_abs&1))
+- trans_coeff_level = -trans_coeff_level;
++
++ // sign_hidden = 0 or 1 so we can combine the tests
++ if ((sign_hidden & sum_abs) != 0) {
++ levels[nb_significant_coeff_flag - 1] = -levels[nb_significant_coeff_flag - 1];
+ }
+- if (coeff_sign_flag >> 15)
+- trans_coeff_level = -trans_coeff_level;
+- coeff_sign_flag <<= 1;
+- if(!lc->cu.cu_transquant_bypass_flag) {
+- if (s->ps.sps->scaling_list_enable_flag && !(transform_skip_flag && log2_trafo_size > 2)) {
+- if(y_c || x_c || log2_trafo_size < 4) {
+- switch(log2_trafo_size) {
+- case 3: pos = (y_c << 3) + x_c; break;
+- case 4: pos = ((y_c >> 1) << 3) + (x_c >> 1); break;
+- case 5: pos = ((y_c >> 2) << 3) + (x_c >> 2); break;
+- default: pos = (y_c << 2) + x_c; break;
+- }
+- scale_m = scale_matrix[pos];
+- } else {
+- scale_m = dc_scale;
+- }
++
++ bypass_finish(s);
++
++ // -- Finish bypass block
++
++ // Scale loop
++ {
++ int m = nb_significant_coeff_flag - 1;
++
++ // Deal with DC component (if any) first
++ if (i == 0 && significant_coeff_flag_idx[m] == 0)
++ {
++ const int k = (int32_t)(coeff_sign_flags << m) >> 31;
++ blk_coeffs[0] = trans_scale_sat(
++ (levels[m] ^ k) - k, scale, dc_scale, shift);
++ --m;
+ }
+- trans_coeff_level = (trans_coeff_level * (int64_t)scale * (int64_t)scale_m + add) >> shift;
+- if(trans_coeff_level < 0) {
+- if((~trans_coeff_level) & 0xFffffffffff8000)
+- trans_coeff_level = -32768;
+- } else {
+- if(trans_coeff_level & 0xffffffffffff8000)
+- trans_coeff_level = 32767;
++
++#if !USE_N_END_1
++ // If N_END_! set then m was at least 1 initially
++ if (m >= 0)
++#endif
++ {
++ do {
++ const xy_off_t * const xy_off = scan_xy_off +
++ significant_coeff_flag_idx[m];
++ const int k = (int32_t)(coeff_sign_flags << m) >> 31;
++
++ blk_coeffs[xy_off->coeff] = trans_scale_sat(
++ (levels[m] ^ k) - k,
++ scale,
++ blk_scale[xy_off->scale],
++ shift);
++ } while (--m >= 0);
+ }
+ }
+- coeffs[y_c * trafo_size + x_c] = trans_coeff_level;
++
+ }
+ }
+- }
++ } while ((i = next_subset(s, i, c_idx_nz,
++ significant_coeff_group_flag, scan_x_cg, scan_y_cg, &prev_sig)) >= 0);
+
+ if (lc->cu.cu_transquant_bypass_flag) {
+ if (explicit_rdpcm_flag || (s->ps.sps->implicit_rdpcm_enabled_flag &&
+@@ -1496,7 +2078,7 @@ void ff_hevc_hls_residual_coding(HEVCContext *s, int x0, int y0,
+ s->hevcdsp.transform_rdpcm(coeffs, log2_trafo_size, mode);
+ }
+ } else {
+- if (transform_skip_flag) {
++ if (trans_skip_or_bypass) { // Must be trans_skip as we've already dealt with bypass
+ int rot = s->ps.sps->transform_skip_rotation_enabled_flag &&
+ log2_trafo_size == 2 &&
+ lc->cu.pred_mode == MODE_INTRA;
+--
+2.5.0
+
+
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-99.1005-0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1005-0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch
new file mode 100644
index 0000000000..bce4e2597b
--- /dev/null
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1005-0001-avcodec-add-h264_mvc-codec-id-and-profiles.patch
@@ -0,0 +1,68 @@
+From f2e011c656b3579b6ede184bb5c56a7b97fad0f3 Mon Sep 17 00:00:00 2001
+From: Hendrik Leppkes
+Date: Sat, 9 Jan 2016 15:34:09 +0100
+Subject: [PATCH] avcodec: add h264_mvc codec id and profiles
+
+avcodec: add h264_mvc codec id and profiles
+---
+ libavcodec/avcodec.h | 5 +++++
+ libavcodec/codec_desc.c | 7 +++++++
+ libavcodec/profiles.c | 3 +++
+ libavformat/mpegts.c | 2 +-
+ 4 files changed, 16 insertions(+), 1 deletion(-)
+
+diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
+index f365775..8498921 100644
+--- a/libavcodec/avcodec.h
++++ b/libavcodec/avcodec.h
+@@ -316,6 +316,8 @@ enum AVCodecID {
+ AV_CODEC_ID_APNG,
+ AV_CODEC_ID_DAALA,
+
++ AV_CODEC_ID_H264_MVC,
++
+ /* various PCM "codecs" */
+ AV_CODEC_ID_FIRST_AUDIO = 0x10000, ///< A dummy id pointing at the start of audio codecs
+ AV_CODEC_ID_PCM_S16LE = 0x10000,
+@@ -3086,6 +3088,9 @@ typedef struct AVCodecContext {
+ #define FF_PROFILE_H264_HIGH_444_PREDICTIVE 244
+ #define FF_PROFILE_H264_HIGH_444_INTRA (244|FF_PROFILE_H264_INTRA)
+ #define FF_PROFILE_H264_CAVLC_444 44
++#define FF_PROFILE_H264_MULTIVIEW_HIGH 118
++#define FF_PROFILE_H264_STEREO_HIGH 128
++#define FF_PROFILE_H264_MULTIVIEW_HIGH_DEPTH 138
+
+ #define FF_PROFILE_VC1_SIMPLE 0
+ #define FF_PROFILE_VC1_MAIN 1
+diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
+index 5fbe624..9431bd8 100644
+--- a/libavcodec/codec_desc.c
++++ b/libavcodec/codec_desc.c
+@@ -1521,6 +1521,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
+ .props = AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/png"),
+ },
++ {
++ .id = AV_CODEC_ID_H264_MVC,
++ .type = AVMEDIA_TYPE_VIDEO,
++ .name = "h264_mvc",
++ .long_name = NULL_IF_CONFIG_SMALL("H264 MVC"),
++ .props = AV_CODEC_PROP_LOSSY,
++ },
+
+ /* various PCM "codecs" */
+ {
+diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
+index 22874e6..34b6987 100644
+--- a/libavformat/mpegts.c
++++ b/libavformat/mpegts.c
+@@ -698,7 +698,7 @@ static const StreamType ISO_types[] = {
+ { 0x11, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC_LATM }, /* LATM syntax */
+ #endif
+ { 0x1b, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
+- { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 },
++ { 0x20, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264_MVC },
+ { 0x21, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_JPEG2000 },
+ { 0x24, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_HEVC },
+ { 0x42, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_CAVS },
+
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-99.1006-0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1006-0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch
new file mode 100644
index 0000000000..fb4028881f
--- /dev/null
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1006-0001-h264_parser-add-support-for-parsing-h264-mvc-NALUs.patch
@@ -0,0 +1,114 @@
+From 0b857974bc3f2f48800526efbe02b9e72fdeb266 Mon Sep 17 00:00:00 2001
+From: Hendrik Leppkes
+Date: Sat, 9 Jan 2016 16:34:40 +0100
+Subject: [PATCH] h264_parser: add support for parsing h264 mvc NALUs
+
+---
+ libavcodec/allcodecs.c | 1 +
+ libavcodec/h264.h | 2 ++
+ libavcodec/h264_parser.c | 34 ++++++++++++++++++++++++++++++----
+ 3 files changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
+index 2097db0..66eb571 100644
+--- a/libavcodec/allcodecs.c
++++ b/libavcodec/allcodecs.c
+@@ -633,6 +633,7 @@ void avcodec_register_all(void)
+ REGISTER_PARSER(H261, h261);
+ REGISTER_PARSER(H263, h263);
+ REGISTER_PARSER(H264, h264);
++ REGISTER_PARSER(H264_MVC, h264_mvc);
+ REGISTER_PARSER(HEVC, hevc);
+ REGISTER_PARSER(MJPEG, mjpeg);
+ REGISTER_PARSER(MLP, mlp);
+diff --git a/libavcodec/h264.h b/libavcodec/h264.h
+index 78f4eed..9e1d377 100644
+--- a/libavcodec/h264.h
++++ b/libavcodec/h264.h
+@@ -123,7 +123,9 @@ enum {
+ NAL_END_STREAM = 11,
+ NAL_FILLER_DATA = 12,
+ NAL_SPS_EXT = 13,
++ NAL_SPS_SUBSET = 15,
+ NAL_AUXILIARY_SLICE = 19,
++ NAL_SLICE_EXT = 20,
+ NAL_FF_IGNORE = 0xff0f001,
+ };
+
+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
+index 12d6397..4337c8c 100644
+--- a/libavcodec/h264_parser.c
++++ b/libavcodec/h264_parser.c
+@@ -38,6 +38,7 @@ typedef struct H264ParseContext {
+ H264Context h;
+ ParseContext pc;
+ int got_first;
++ int is_mvc;
+ } H264ParseContext;
+
+
+@@ -86,14 +87,18 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf,
+ } else if (state <= 5) {
+ int nalu_type = buf[i] & 0x1F;
+ if (nalu_type == NAL_SEI || nalu_type == NAL_SPS ||
+- nalu_type == NAL_PPS || nalu_type == NAL_AUD) {
++ nalu_type == NAL_PPS || nalu_type == NAL_AUD ||
++ nalu_type == NAL_SPS_SUBSET) {
+ if (pc->frame_start_found) {
+ i++;
+ goto found;
+ }
+ } else if (nalu_type == NAL_SLICE || nalu_type == NAL_DPA ||
+- nalu_type == NAL_IDR_SLICE) {
++ nalu_type == NAL_IDR_SLICE || (p->is_mvc && nalu_type == NAL_SLICE_EXT)) {
+ state += 8;
++
++ if (nalu_type == NAL_SLICE_EXT)
++ i += 3; // skip mvc extension
+ continue;
+ }
+ state = 7;
+@@ -532,7 +537,8 @@ static int h264_parse(AVCodecParserContext *s,
+ }
+ }
+
+- parse_nal_units(s, avctx, buf, buf_size);
++ if (!p->is_mvc)
++ parse_nal_units(s, avctx, buf, buf_size);
+
+ if (avctx->framerate.num)
+ avctx->time_base = av_inv_q(av_mul_q(avctx->framerate, (AVRational){avctx->ticks_per_frame, 1}));
+@@ -569,7 +575,7 @@ static int h264_split(AVCodecContext *avctx,
+ if ((state & 0xFFFFFF00) != 0x100)
+ break;
+ nalu_type = state & 0x1F;
+- if (nalu_type == NAL_SPS) {
++ if (nalu_type == NAL_SPS || nalu_type == NAL_SPS_SUBSET) {
+ has_sps = 1;
+ } else if (nalu_type == NAL_PPS)
+ has_pps = 1;
+@@ -625,3 +631,23 @@ AVCodecParser ff_h264_parser = {
+ .parser_close = h264_close,
+ .split = h264_split,
+ };
++
++static av_cold int init_mvc(AVCodecParserContext *s)
++{
++ H264ParseContext *p = s->priv_data;
++ int ret = init(s);
++ if (ret < 0)
++ return ret;
++
++ p->is_mvc = 1;
++ return 0;
++}
++
++AVCodecParser ff_h264_mvc_parser = {
++ .codec_ids = { AV_CODEC_ID_H264_MVC },
++ .priv_data_size = sizeof(H264ParseContext),
++ .parser_init = init_mvc,
++ .parser_parse = h264_parse,
++ .parser_close = h264_close,
++ .split = h264_split,
++};
+
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-99.1007-h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1007-h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch
new file mode 100644
index 0000000000..8b89f53518
--- /dev/null
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1007-h264_parser_fix_parsing_of_mvc_slices_in_some_corner_cases.patch
@@ -0,0 +1,67 @@
+From fd627f6435db524f3e1fd8df6f64a17dcda5c8b9 Mon Sep 17 00:00:00 2001
+From: Hendrik Leppkes
+Date: Fri, 26 Feb 2016 00:23:53 +0100
+Subject: [PATCH] h264_parser: fix parsing of mvc slices in some corner cases
+
+---
+ libavcodec/h264.h | 2 +-
+ libavcodec/h264_parser.c | 10 +++++-----
+ 2 files changed, 6 insertions(+), 6 deletions(-)
+
+diff --git a/libavcodec/h264.h b/libavcodec/h264.h
+index 9e1d377..846e4dc 100644
+--- a/libavcodec/h264.h
++++ b/libavcodec/h264.h
+@@ -828,7 +828,7 @@ typedef struct H264Context {
+ int cur_bit_depth_luma;
+ int16_t slice_row[MAX_SLICES]; ///< to detect when MAX_SLICES is too low
+
+- uint8_t parse_history[6];
++ uint8_t parse_history[9];
+ int parse_history_count;
+ int parse_last_mb;
+
+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
+index 4337c8c..2fd3f2b 100644
+--- a/libavcodec/h264_parser.c
++++ b/libavcodec/h264_parser.c
+@@ -39,6 +39,7 @@ typedef struct H264ParseContext {
+ ParseContext pc;
+ int got_first;
+ int is_mvc;
++ int slice_ext;
+ } H264ParseContext;
+
+
+@@ -97,18 +98,17 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf,
+ nalu_type == NAL_IDR_SLICE || (p->is_mvc && nalu_type == NAL_SLICE_EXT)) {
+ state += 8;
+
+- if (nalu_type == NAL_SLICE_EXT)
+- i += 3; // skip mvc extension
++ p->slice_ext = (nalu_type == NAL_SLICE_EXT);
+ continue;
+ }
+ state = 7;
+ } else {
+ h->parse_history[h->parse_history_count++]= buf[i];
+- if (h->parse_history_count>5) {
++ if (h->parse_history_count>8) {
+ unsigned int mb, last_mb= h->parse_last_mb;
+ GetBitContext gb;
+
+- init_get_bits(&gb, h->parse_history, 8*h->parse_history_count);
++ init_get_bits8(&gb, h->parse_history + 3*p->slice_ext, h->parse_history_count - 3*p->slice_ext);
+ h->parse_history_count=0;
+ mb= get_ue_golomb_long(&gb);
+ h->parse_last_mb= mb;
+@@ -131,7 +131,7 @@ static int h264_find_frame_end(H264ParseContext *p, const uint8_t *buf,
+ pc->frame_start_found = 0;
+ if (h->is_avc)
+ return next_avc;
+- return i - (state & 5) - 5 * (state > 7);
++ return i - (state & 5) - 8 * (state > 7);
+ }
+
+ static int scan_mmco_reset(AVCodecParserContext *s)
+
diff --git a/packages/multimedia/ffmpeg/patches/ffmpeg-99.1008-73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1008-73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch
new file mode 100644
index 0000000000..721a065449
--- /dev/null
+++ b/packages/multimedia/ffmpeg/patches/ffmpeg-99.1008-73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105.patch
@@ -0,0 +1,25 @@
+From 73fde6f9f3d01f7fc0f3ae4b66f6c725f9fb1105 Mon Sep 17 00:00:00 2001
+From: Hendrik Leppkes
+Date: Mon, 1 Sep 2014 11:39:09 +0200
+Subject: [PATCH] h264_parser: force grabing a new timestamp until a frame
+ start was found
+
+---
+ libavcodec/h264_parser.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
+index 2fd3f2b..7165652 100644
+--- a/libavcodec/h264_parser.c
++++ b/libavcodec/h264_parser.c
+@@ -525,6 +525,9 @@ static int h264_parse(AVCodecParserContext *s,
+ } else {
+ next = h264_find_frame_end(p, buf, buf_size);
+
++ if (next == END_NOT_FOUND && pc->frame_start_found == 0)
++ s->fetch_timestamp = 1;
++
+ if (ff_combine_frame(pc, next, &buf, &buf_size) < 0) {
+ *poutbuf = NULL;
+ *poutbuf_size = 0;
+