|  | @@ -1,20665 +0,0 @@
 | 
	
		
			
				|  |  | -From 1353d8feca19f2f84019797942d70864054db1b0 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Mon, 5 Aug 2013 13:12:46 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 01/94] h264_parser: Initialize the h264dsp context in the
 | 
	
		
			
				|  |  | - parser as well
 | 
	
		
			
				|  |  | -MIME-Version: 1.0
 | 
	
		
			
				|  |  | -Content-Type: text/plain; charset=UTF-8
 | 
	
		
			
				|  |  | -Content-Transfer-Encoding: 8bit
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Each AVStream struct for an H.264 elementary stream actually has two
 | 
	
		
			
				|  |  | -copies of the H264DSPContext struct (and in fact all the other members
 | 
	
		
			
				|  |  | -of H264Context as well):
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -((H264Context *) ((AVStream *)st)->codec->priv_data)->h264dsp
 | 
	
		
			
				|  |  | -((H264Context *) ((AVStream *)st)->parser->priv_data)->h264dsp
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -but only the first of these was actually being initialised. This
 | 
	
		
			
				|  |  | -prevented the addition of platform-specific implementations of
 | 
	
		
			
				|  |  | -parser-related functions.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Signed-off-by: Martin Storsjö <martin@martin.st>
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/h264_parser.c | 1 +
 | 
	
		
			
				|  |  | - 1 file changed, 1 insertion(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/h264_parser.c b/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -index aff9ba1..a732f79 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -@@ -386,6 +386,7 @@ static int init(AVCodecParserContext *s)
 | 
	
		
			
				|  |  | -     H264Context *h = s->priv_data;
 | 
	
		
			
				|  |  | -     h->thread_context[0] = h;
 | 
	
		
			
				|  |  | -     h->slice_context_count = 1;
 | 
	
		
			
				|  |  | -+    ff_h264dsp_init(&h->h264dsp, 8, 1);
 | 
	
		
			
				|  |  | -     return 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7ea2cb68f6fb1149fce70854e36ed6357a267238 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Mon, 5 Aug 2013 13:12:47 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 02/94] h264dsp: Factorize code into a new function,
 | 
	
		
			
				|  |  | - h264_find_start_code_candidate
 | 
	
		
			
				|  |  | -MIME-Version: 1.0
 | 
	
		
			
				|  |  | -Content-Type: text/plain; charset=UTF-8
 | 
	
		
			
				|  |  | -Content-Transfer-Encoding: 8bit
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This performs the start code search which was previously part of
 | 
	
		
			
				|  |  | -h264_find_frame_end() - the most CPU intensive part of the function.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -By itself, this results in a performance regression:
 | 
	
		
			
				|  |  | -              Before          After
 | 
	
		
			
				|  |  | -              Mean   StdDev   Mean   StdDev  Change
 | 
	
		
			
				|  |  | -Overall time  2925.6 26.2     3068.5 31.7    -4.7%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -but this can more than be made up for by platform-optimised
 | 
	
		
			
				|  |  | -implementations of the function.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Signed-off-by: Martin Storsjö <martin@martin.st>
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/h264_parser.c | 20 +++-----------------
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/h264dsp.c     | 29 +++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/h264dsp.h     |  9 +++++++++
 | 
	
		
			
				|  |  | - 3 files changed, 41 insertions(+), 17 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/h264_parser.c b/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -index a732f79..972aace 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -@@ -62,23 +62,9 @@ static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_si
 | 
	
		
			
				|  |  | -         }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         if(state==7){
 | 
	
		
			
				|  |  | --#if HAVE_FAST_UNALIGNED
 | 
	
		
			
				|  |  | --        /* we check i<buf_size instead of i+3/7 because its simpler
 | 
	
		
			
				|  |  | --         * and there should be FF_INPUT_BUFFER_PADDING_SIZE bytes at the end
 | 
	
		
			
				|  |  | --         */
 | 
	
		
			
				|  |  | --#    if HAVE_FAST_64BIT
 | 
	
		
			
				|  |  | --            while(i<next_avc && !((~*(const uint64_t*)(buf+i) & (*(const uint64_t*)(buf+i) - 0x0101010101010101ULL)) & 0x8080808080808080ULL))
 | 
	
		
			
				|  |  | --                i+=8;
 | 
	
		
			
				|  |  | --#    else
 | 
	
		
			
				|  |  | --            while(i<next_avc && !((~*(const uint32_t*)(buf+i) & (*(const uint32_t*)(buf+i) - 0x01010101U)) & 0x80808080U))
 | 
	
		
			
				|  |  | --                i+=4;
 | 
	
		
			
				|  |  | --#    endif
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --            for(; i<next_avc; i++){
 | 
	
		
			
				|  |  | --                if(!buf[i]){
 | 
	
		
			
				|  |  | --                    state=2;
 | 
	
		
			
				|  |  | --                    break;
 | 
	
		
			
				|  |  | --                }
 | 
	
		
			
				|  |  | -+            i += h->h264dsp.h264_find_start_code_candidate(buf + i, buf_size - i);
 | 
	
		
			
				|  |  | -+            if (i < buf_size)
 | 
	
		
			
				|  |  | -+                state = 2;
 | 
	
		
			
				|  |  | -             }
 | 
	
		
			
				|  |  | -         }else if(state<=2){
 | 
	
		
			
				|  |  | -             if(buf[i]==1)   state^= 5; //2->7, 1->4, 0->5
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/h264dsp.c b/lib/ffmpeg/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -index da9e417..b7d61cd 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -@@ -60,6 +60,34 @@
 | 
	
		
			
				|  |  | - #include "h264addpx_template.c"
 | 
	
		
			
				|  |  | - #undef BIT_DEPTH
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+static int h264_find_start_code_candidate_c(const uint8_t *buf, int size)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    int i = 0;
 | 
	
		
			
				|  |  | -+#if HAVE_FAST_UNALIGNED
 | 
	
		
			
				|  |  | -+    /* we check i < size instead of i + 3 / 7 because it is
 | 
	
		
			
				|  |  | -+     * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
 | 
	
		
			
				|  |  | -+     * bytes at the end.
 | 
	
		
			
				|  |  | -+     */
 | 
	
		
			
				|  |  | -+#if HAVE_FAST_64BIT
 | 
	
		
			
				|  |  | -+    while (i < size &&
 | 
	
		
			
				|  |  | -+            !((~*(const uint64_t *)(buf + i) &
 | 
	
		
			
				|  |  | -+                    (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
 | 
	
		
			
				|  |  | -+                    0x8080808080808080ULL))
 | 
	
		
			
				|  |  | -+        i += 8;
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -+    while (i < size &&
 | 
	
		
			
				|  |  | -+            !((~*(const uint32_t *)(buf + i) &
 | 
	
		
			
				|  |  | -+                    (*(const uint32_t *)(buf + i) - 0x01010101U)) &
 | 
	
		
			
				|  |  | -+                    0x80808080U))
 | 
	
		
			
				|  |  | -+        i += 4;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+    for (; i < size; i++)
 | 
	
		
			
				|  |  | -+        if (!buf[i])
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+    return i;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_format_idc)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - #undef FUNC
 | 
	
		
			
				|  |  | -@@ -146,6 +174,7 @@ void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_fo
 | 
	
		
			
				|  |  | -         H264_DSP(8);
 | 
	
		
			
				|  |  | -         break;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+    c->h264_find_start_code_candidate = h264_find_start_code_candidate_c;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (ARCH_ARM) ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | -     if (HAVE_ALTIVEC) ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/h264dsp.h b/lib/ffmpeg/libavcodec/h264dsp.h
 | 
	
		
			
				|  |  | -index 98ea15c..1be4804 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/h264dsp.h
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/h264dsp.h
 | 
	
		
			
				|  |  | -@@ -105,6 +105,15 @@ typedef struct H264DSPContext {
 | 
	
		
			
				|  |  | -     /* bypass-transform */
 | 
	
		
			
				|  |  | -     void (*h264_add_pixels8_clear)(uint8_t *dst, int16_t *block, int stride);
 | 
	
		
			
				|  |  | -     void (*h264_add_pixels4_clear)(uint8_t *dst, int16_t *block, int stride);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    /**
 | 
	
		
			
				|  |  | -+     * Search buf from the start for up to size bytes. Return the index
 | 
	
		
			
				|  |  | -+     * of a zero byte, or >= size if not found. Ideally, use lookahead
 | 
	
		
			
				|  |  | -+     * to filter out any zero bytes that are known to not be followed by
 | 
	
		
			
				|  |  | -+     * one or more further zero bytes and a one byte. Better still, filter
 | 
	
		
			
				|  |  | -+     * out any bytes that form the trailing_zero_8bits syntax element too.
 | 
	
		
			
				|  |  | -+     */
 | 
	
		
			
				|  |  | -+    int (*h264_find_start_code_candidate)(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | - } H264DSPContext;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 458ff4b6c1855c529f563dbbd15e35aaab50adae Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Mon, 5 Aug 2013 13:12:48 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 03/94] arm: Add assembly version of
 | 
	
		
			
				|  |  | - h264_find_start_code_candidate
 | 
	
		
			
				|  |  | -MIME-Version: 1.0
 | 
	
		
			
				|  |  | -Content-Type: text/plain; charset=UTF-8
 | 
	
		
			
				|  |  | -Content-Transfer-Encoding: 8bit
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -               Before          After
 | 
	
		
			
				|  |  | -               Mean   StdDev   Mean   StdDev  Change
 | 
	
		
			
				|  |  | -This function   508.8 23.4      185.4  9.0    +174.4%
 | 
	
		
			
				|  |  | -Overall        3068.5 31.7     2752.1 29.4     +11.5%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -In combination with the preceding patch:
 | 
	
		
			
				|  |  | -                Before          After
 | 
	
		
			
				|  |  | -                Mean   StdDev   Mean   StdDev  Change
 | 
	
		
			
				|  |  | -Overall         2925.6 26.2     2752.1 29.4     +6.3%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Signed-off-by: Martin Storsjö <martin@martin.st>
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/Makefile           |   1 +
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S    | 253 +++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c |   4 +
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/h264_parser.c          |   1 -
 | 
	
		
			
				|  |  | - 4 files changed, 258 insertions(+), 1 deletion(-)
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -index 7390a8b..480000b71 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -@@ -9,6 +9,7 @@ OBJS-$(CONFIG_AAC_DECODER)             += arm/sbrdsp_init_arm.o         \
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_DCA_DECODER)             += arm/dcadsp_init_arm.o         \
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - ARMV6-OBJS-$(CONFIG_AC3DSP)            += arm/ac3dsp_armv6.o
 | 
	
		
			
				|  |  | -+ARMV6-OBJS-$(CONFIG_H264DSP)           += arm/h264dsp_armv6.o
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_FLAC_DECODER)            += arm/flacdsp_init_arm.o        \
 | 
	
		
			
				|  |  | -                                           arm/flacdsp_arm.o             \
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S b/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..c4f12a6
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -@@ -0,0 +1,253 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ * Copyright (c) 2013 RISC OS Open Ltd
 | 
	
		
			
				|  |  | -+ * Author: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * This file is part of Libav.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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 Libav; if not, write to the Free Software
 | 
	
		
			
				|  |  | -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "libavutil/arm/asm.S"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+RESULT  .req    a1
 | 
	
		
			
				|  |  | -+BUF     .req    a1
 | 
	
		
			
				|  |  | -+SIZE    .req    a2
 | 
	
		
			
				|  |  | -+PATTERN .req    a3
 | 
	
		
			
				|  |  | -+PTR     .req    a4
 | 
	
		
			
				|  |  | -+DAT0    .req    v1
 | 
	
		
			
				|  |  | -+DAT1    .req    v2
 | 
	
		
			
				|  |  | -+DAT2    .req    v3
 | 
	
		
			
				|  |  | -+DAT3    .req    v4
 | 
	
		
			
				|  |  | -+TMP0    .req    v5
 | 
	
		
			
				|  |  | -+TMP1    .req    v6
 | 
	
		
			
				|  |  | -+TMP2    .req    ip
 | 
	
		
			
				|  |  | -+TMP3    .req    lr
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define PRELOAD_DISTANCE 4
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro innerloop4
 | 
	
		
			
				|  |  | -+        ldr     DAT0, [PTR], #4
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #4 @ C flag survives rest of macro
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro innerloop16  decrement, do_preload
 | 
	
		
			
				|  |  | -+        ldmia   PTR!, {DAT0,DAT1,DAT2,DAT3}
 | 
	
		
			
				|  |  | -+ .ifnc "\do_preload",""
 | 
	
		
			
				|  |  | -+        pld     [PTR, #PRELOAD_DISTANCE*32]
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .ifnc "\decrement",""
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #\decrement @ C flag survives rest of macro
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        sub     TMP1, DAT1, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        bic     TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | -+        sub     TMP2, DAT2, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        sub     TMP3, DAT3, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | -+        bic     TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        andseq  TMP1, TMP1, PATTERN
 | 
	
		
			
				|  |  | -+        bic     TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | -+        itt     eq
 | 
	
		
			
				|  |  | -+        andseq  TMP2, TMP2, PATTERN
 | 
	
		
			
				|  |  | -+        andseq  TMP3, TMP3, PATTERN
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/* int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size) */
 | 
	
		
			
				|  |  | -+function ff_h264_find_start_code_candidate_armv6, export=1
 | 
	
		
			
				|  |  | -+        push    {v1-v6,lr}
 | 
	
		
			
				|  |  | -+        mov     PTR, BUF
 | 
	
		
			
				|  |  | -+        @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
 | 
	
		
			
				|  |  | -+        @ before using code that does preloads
 | 
	
		
			
				|  |  | -+        cmp     SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
 | 
	
		
			
				|  |  | -+        blo     60f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        @ Get to word-alignment, 1 byte at a time
 | 
	
		
			
				|  |  | -+        tst     PTR, #3
 | 
	
		
			
				|  |  | -+        beq     2f
 | 
	
		
			
				|  |  | -+1:      ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -+        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        tst     PTR, #3
 | 
	
		
			
				|  |  | -+        bne     1b
 | 
	
		
			
				|  |  | -+2:      @ Get to 4-word alignment, 1 word at a time
 | 
	
		
			
				|  |  | -+        ldr     PATTERN, =0x80008000
 | 
	
		
			
				|  |  | -+        setend  be
 | 
	
		
			
				|  |  | -+        tst     PTR, #12
 | 
	
		
			
				|  |  | -+        beq     4f
 | 
	
		
			
				|  |  | -+3:      innerloop4
 | 
	
		
			
				|  |  | -+        bne     91f
 | 
	
		
			
				|  |  | -+        tst     PTR, #12
 | 
	
		
			
				|  |  | -+        bne     3b
 | 
	
		
			
				|  |  | -+4:      @ Get to cacheline (8-word) alignment
 | 
	
		
			
				|  |  | -+        tst     PTR, #16
 | 
	
		
			
				|  |  | -+        beq     5f
 | 
	
		
			
				|  |  | -+        innerloop16  16
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+5:      @ Check complete cachelines, with preloading
 | 
	
		
			
				|  |  | -+        @ We need to stop when there are still (PRELOAD_DISTANCE+1)
 | 
	
		
			
				|  |  | -+        @ complete cachelines to go
 | 
	
		
			
				|  |  | -+        sub     SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
 | 
	
		
			
				|  |  | -+6:      innerloop16  , do_preload
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+        innerloop16  32
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+        bcs     6b
 | 
	
		
			
				|  |  | -+        @ Preload trailing part-cacheline, if any
 | 
	
		
			
				|  |  | -+        tst     SIZE, #31
 | 
	
		
			
				|  |  | -+        beq     7f
 | 
	
		
			
				|  |  | -+        pld     [PTR, #(PRELOAD_DISTANCE+1)*32]
 | 
	
		
			
				|  |  | -+        @ Check remaining data without doing any more preloads. First
 | 
	
		
			
				|  |  | -+        @ do in chunks of 4 words:
 | 
	
		
			
				|  |  | -+7:      adds    SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
 | 
	
		
			
				|  |  | -+        bmi     9f
 | 
	
		
			
				|  |  | -+8:      innerloop16  16
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+        bcs     8b
 | 
	
		
			
				|  |  | -+        @ Then in words:
 | 
	
		
			
				|  |  | -+9:      adds    SIZE, SIZE, #16 - 4
 | 
	
		
			
				|  |  | -+        bmi     11f
 | 
	
		
			
				|  |  | -+10:     innerloop4
 | 
	
		
			
				|  |  | -+        bne     91f
 | 
	
		
			
				|  |  | -+        bcs     10b
 | 
	
		
			
				|  |  | -+11:     setend  le
 | 
	
		
			
				|  |  | -+        @ Check second byte of final halfword
 | 
	
		
			
				|  |  | -+        ldrb    DAT0, [PTR, #-1]
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        @ Check any remaining bytes
 | 
	
		
			
				|  |  | -+        tst     SIZE, #3
 | 
	
		
			
				|  |  | -+        beq     13f
 | 
	
		
			
				|  |  | -+12:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -+        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        tst     SIZE, #3
 | 
	
		
			
				|  |  | -+        bne     12b
 | 
	
		
			
				|  |  | -+        @ No candidate found
 | 
	
		
			
				|  |  | -+13:     sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        b       99f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+60:     @ Small buffer - simply check by looping over bytes
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        bcc     99f
 | 
	
		
			
				|  |  | -+61:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        bcs     61b
 | 
	
		
			
				|  |  | -+        @ No candidate found
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        b       99f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+90:     @ Found a candidate at the preceding byte
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        sub     RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       99f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+91:     @ Found a candidate somewhere in the preceding 4 bytes
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        sub     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        itt     pl
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        bpl     92f
 | 
	
		
			
				|  |  | -+        teq     RESULT, #0
 | 
	
		
			
				|  |  | -+        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | -+        ldrb    DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | -+92:     teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+93:     @ Found a candidate somewhere in the preceding 16 bytes
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        sub     RESULT, RESULT, #16
 | 
	
		
			
				|  |  | -+        teq     TMP0, #0
 | 
	
		
			
				|  |  | -+        beq     95f @ not in first 4 bytes
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        itt     pl
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-15]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        bpl     94f
 | 
	
		
			
				|  |  | -+        teq     RESULT, #0
 | 
	
		
			
				|  |  | -+        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | -+        ldrb    DAT0, [PTR, #-17]
 | 
	
		
			
				|  |  | -+94:     teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+95:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        teq     TMP1, #0
 | 
	
		
			
				|  |  | -+        beq     96f @ not in next 4 bytes
 | 
	
		
			
				|  |  | -+        sub     TMP1, DAT1, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | -+        itee    mi
 | 
	
		
			
				|  |  | -+        ldrbmi  DAT0, [PTR, #-13]
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-11]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+96:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        teq     TMP2, #0
 | 
	
		
			
				|  |  | -+        beq     97f @ not in next 4 bytes
 | 
	
		
			
				|  |  | -+        sub     TMP2, DAT2, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | -+        itee    mi
 | 
	
		
			
				|  |  | -+        ldrbmi  DAT0, [PTR, #-9]
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-7]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+97:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        sub     TMP3, DAT3, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | -+        itee    mi
 | 
	
		
			
				|  |  | -+        ldrbmi  DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        @ drop through to 98f
 | 
	
		
			
				|  |  | -+98:     setend  le
 | 
	
		
			
				|  |  | -+99:     pop     {v1-v6,pc}
 | 
	
		
			
				|  |  | -+.endfunc
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        .unreq  RESULT
 | 
	
		
			
				|  |  | -+        .unreq  BUF
 | 
	
		
			
				|  |  | -+        .unreq  SIZE
 | 
	
		
			
				|  |  | -+        .unreq  PATTERN
 | 
	
		
			
				|  |  | -+        .unreq  PTR
 | 
	
		
			
				|  |  | -+        .unreq  DAT0
 | 
	
		
			
				|  |  | -+        .unreq  DAT1
 | 
	
		
			
				|  |  | -+        .unreq  DAT2
 | 
	
		
			
				|  |  | -+        .unreq  DAT3
 | 
	
		
			
				|  |  | -+        .unreq  TMP0
 | 
	
		
			
				|  |  | -+        .unreq  TMP1
 | 
	
		
			
				|  |  | -+        .unreq  TMP2
 | 
	
		
			
				|  |  | -+        .unreq  TMP3
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -index 785b604..2804e56 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -@@ -24,6 +24,8 @@
 | 
	
		
			
				|  |  | - #include "libavutil/arm/cpu.h"
 | 
	
		
			
				|  |  | - #include "libavcodec/h264dsp.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
 | 
	
		
			
				|  |  | -                                      int beta, int8_t *tc0);
 | 
	
		
			
				|  |  | - void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
 | 
	
		
			
				|  |  | -@@ -106,6 +108,8 @@ av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -     int cpu_flags = av_get_cpu_flags();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    if (have_armv6(cpu_flags))
 | 
	
		
			
				|  |  | -+        c->h264_find_start_code_candidate = ff_h264_find_start_code_candidate_armv6;
 | 
	
		
			
				|  |  | -     if (have_neon(cpu_flags))
 | 
	
		
			
				|  |  | -         ff_h264dsp_init_neon(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/h264_parser.c b/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -index 972aace..363843c 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -@@ -65,7 +65,6 @@ static int ff_h264_find_frame_end(H264Context *h, const uint8_t *buf, int buf_si
 | 
	
		
			
				|  |  | -             i += h->h264dsp.h264_find_start_code_candidate(buf + i, buf_size - i);
 | 
	
		
			
				|  |  | -             if (i < buf_size)
 | 
	
		
			
				|  |  | -                 state = 2;
 | 
	
		
			
				|  |  | --            }
 | 
	
		
			
				|  |  | -         }else if(state<=2){
 | 
	
		
			
				|  |  | -             if(buf[i]==1)   state^= 5; //2->7, 1->4, 0->5
 | 
	
		
			
				|  |  | -             else if(buf[i]) state = 7;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 5841d5b69f0df2f286c0a8e419deb16d927e864e Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 19 Aug 2013 22:48:05 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 04/94] [ffmpeg] Backport of h264_find_start_code_candidate
 | 
	
		
			
				|  |  | - optimisation
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - ...-Initialize-the-h264dsp-context-in-the-pa.patch |  39 +++
 | 
	
		
			
				|  |  | - ...torize-code-into-a-new-function-h264_find.patch | 134 +++++++++
 | 
	
		
			
				|  |  | - ...embly-version-of-h264_find_start_code_can.patch | 322 +++++++++++++++++++++
 | 
	
		
			
				|  |  | - 3 files changed, 495 insertions(+)
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch b/lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..263578d
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/patches/0056-h264_parser-Initialize-the-h264dsp-context-in-the-pa.patch
 | 
	
		
			
				|  |  | -@@ -0,0 +1,39 @@
 | 
	
		
			
				|  |  | -+From 7a82022ee2f9b1fad991ace0936901e7419444be Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -+From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -+Date: Mon, 5 Aug 2013 13:12:46 +0100
 | 
	
		
			
				|  |  | -+Subject: [PATCH 1/3] h264_parser: Initialize the h264dsp context in the
 | 
	
		
			
				|  |  | -+ parser as well
 | 
	
		
			
				|  |  | -+MIME-Version: 1.0
 | 
	
		
			
				|  |  | -+Content-Type: text/plain; charset=UTF-8
 | 
	
		
			
				|  |  | -+Content-Transfer-Encoding: 8bit
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+Each AVStream struct for an H.264 elementary stream actually has two
 | 
	
		
			
				|  |  | -+copies of the H264DSPContext struct (and in fact all the other members
 | 
	
		
			
				|  |  | -+of H264Context as well):
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+((H264Context *) ((AVStream *)st)->codec->priv_data)->h264dsp
 | 
	
		
			
				|  |  | -+((H264Context *) ((AVStream *)st)->parser->priv_data)->h264dsp
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+but only the first of these was actually being initialised. This
 | 
	
		
			
				|  |  | -+prevented the addition of platform-specific implementations of
 | 
	
		
			
				|  |  | -+parser-related functions.
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+Signed-off-by: Martin Storsjö <martin@martin.st>
 | 
	
		
			
				|  |  | -+---
 | 
	
		
			
				|  |  | -+ libavcodec/h264_parser.c |    1 +
 | 
	
		
			
				|  |  | -+ 1 file changed, 1 insertion(+)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -+index 2ed155c..da2a5f9 100644
 | 
	
		
			
				|  |  | -+--- a/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -++++ b/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -+@@ -417,6 +417,7 @@ static av_cold int init(AVCodecParserContext *s)
 | 
	
		
			
				|  |  | -+     H264Context *h = s->priv_data;
 | 
	
		
			
				|  |  | -+     h->thread_context[0]   = h;
 | 
	
		
			
				|  |  | -+     h->slice_context_count = 1;
 | 
	
		
			
				|  |  | -++    ff_h264dsp_init(&h->h264dsp, 8, 1);
 | 
	
		
			
				|  |  | -+     return 0;
 | 
	
		
			
				|  |  | -+ }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+--
 | 
	
		
			
				|  |  | -+1.7.9.5
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch b/lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..0151d85
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/patches/0057-h264dsp-Factorize-code-into-a-new-function-h264_find.patch
 | 
	
		
			
				|  |  | -@@ -0,0 +1,134 @@
 | 
	
		
			
				|  |  | -+From 218d6844b37d339ffbf2044ad07d8be7767e2734 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -+From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -+Date: Mon, 5 Aug 2013 13:12:47 +0100
 | 
	
		
			
				|  |  | -+Subject: [PATCH 2/3] h264dsp: Factorize code into a new function,
 | 
	
		
			
				|  |  | -+ h264_find_start_code_candidate
 | 
	
		
			
				|  |  | -+MIME-Version: 1.0
 | 
	
		
			
				|  |  | -+Content-Type: text/plain; charset=UTF-8
 | 
	
		
			
				|  |  | -+Content-Transfer-Encoding: 8bit
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+This performs the start code search which was previously part of
 | 
	
		
			
				|  |  | -+h264_find_frame_end() - the most CPU intensive part of the function.
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+By itself, this results in a performance regression:
 | 
	
		
			
				|  |  | -+              Before          After
 | 
	
		
			
				|  |  | -+              Mean   StdDev   Mean   StdDev  Change
 | 
	
		
			
				|  |  | -+Overall time  2925.6 26.2     3068.5 31.7    -4.7%
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+but this can more than be made up for by platform-optimised
 | 
	
		
			
				|  |  | -+implementations of the function.
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+Signed-off-by: Martin Storsjö <martin@martin.st>
 | 
	
		
			
				|  |  | -+---
 | 
	
		
			
				|  |  | -+ libavcodec/h264_parser.c |   27 +++------------------------
 | 
	
		
			
				|  |  | -+ libavcodec/h264dsp.c     |   29 +++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | -+ libavcodec/h264dsp.h     |    9 +++++++++
 | 
	
		
			
				|  |  | -+ 3 files changed, 41 insertions(+), 24 deletions(-)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+diff --git a/libavcodec/h264_parser.c b/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -+index da2a5f9..ef5da98 100644
 | 
	
		
			
				|  |  | -+--- a/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -++++ b/libavcodec/h264_parser.c
 | 
	
		
			
				|  |  | -+@@ -47,30 +47,9 @@ static int h264_find_frame_end(H264Context *h, const uint8_t *buf,
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+     for (i = 0; i < buf_size; i++) {
 | 
	
		
			
				|  |  | -+         if (state == 7) {
 | 
	
		
			
				|  |  | -+-#if HAVE_FAST_UNALIGNED
 | 
	
		
			
				|  |  | -+-            /* we check i < buf_size instead of i + 3 / 7 because it is
 | 
	
		
			
				|  |  | -+-             * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
 | 
	
		
			
				|  |  | -+-             * bytes at the end.
 | 
	
		
			
				|  |  | -+-             */
 | 
	
		
			
				|  |  | -+-#if HAVE_FAST_64BIT
 | 
	
		
			
				|  |  | -+-            while (i < buf_size &&
 | 
	
		
			
				|  |  | -+-                   !((~*(const uint64_t *)(buf + i) &
 | 
	
		
			
				|  |  | -+-                      (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
 | 
	
		
			
				|  |  | -+-                      0x8080808080808080ULL))
 | 
	
		
			
				|  |  | -+-                i += 8;
 | 
	
		
			
				|  |  | -+-#else
 | 
	
		
			
				|  |  | -+-            while (i < buf_size &&
 | 
	
		
			
				|  |  | -+-                   !((~*(const uint32_t *)(buf + i) &
 | 
	
		
			
				|  |  | -+-                      (*(const uint32_t *)(buf + i) - 0x01010101U)) &
 | 
	
		
			
				|  |  | -+-                      0x80808080U))
 | 
	
		
			
				|  |  | -+-                i += 4;
 | 
	
		
			
				|  |  | -+-#endif
 | 
	
		
			
				|  |  | -+-#endif
 | 
	
		
			
				|  |  | -+-            for (; i < buf_size; i++)
 | 
	
		
			
				|  |  | -+-                if (!buf[i]) {
 | 
	
		
			
				|  |  | -+-                    state = 2;
 | 
	
		
			
				|  |  | -+-                    break;
 | 
	
		
			
				|  |  | -+-                }
 | 
	
		
			
				|  |  | -++            i += h->h264dsp.h264_find_start_code_candidate(buf + i, buf_size - i);
 | 
	
		
			
				|  |  | -++            if (i < buf_size)
 | 
	
		
			
				|  |  | -++                state = 2;
 | 
	
		
			
				|  |  | -+         } else if (state <= 2) {
 | 
	
		
			
				|  |  | -+             if (buf[i] == 1)
 | 
	
		
			
				|  |  | -+                 state ^= 5;            // 2->7, 1->4, 0->5
 | 
	
		
			
				|  |  | -+diff --git a/libavcodec/h264dsp.c b/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -+index 3ca6abe..a901dbb 100644
 | 
	
		
			
				|  |  | -+--- a/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -++++ b/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -+@@ -53,6 +53,34 @@
 | 
	
		
			
				|  |  | -+ #include "h264addpx_template.c"
 | 
	
		
			
				|  |  | -+ #undef BIT_DEPTH
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -++static int h264_find_start_code_candidate_c(const uint8_t *buf, int size)
 | 
	
		
			
				|  |  | -++{
 | 
	
		
			
				|  |  | -++    int i = 0;
 | 
	
		
			
				|  |  | -++#if HAVE_FAST_UNALIGNED
 | 
	
		
			
				|  |  | -++    /* we check i < size instead of i + 3 / 7 because it is
 | 
	
		
			
				|  |  | -++     * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
 | 
	
		
			
				|  |  | -++     * bytes at the end.
 | 
	
		
			
				|  |  | -++     */
 | 
	
		
			
				|  |  | -++#if HAVE_FAST_64BIT
 | 
	
		
			
				|  |  | -++    while (i < size &&
 | 
	
		
			
				|  |  | -++            !((~*(const uint64_t *)(buf + i) &
 | 
	
		
			
				|  |  | -++                    (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
 | 
	
		
			
				|  |  | -++                    0x8080808080808080ULL))
 | 
	
		
			
				|  |  | -++        i += 8;
 | 
	
		
			
				|  |  | -++#else
 | 
	
		
			
				|  |  | -++    while (i < size &&
 | 
	
		
			
				|  |  | -++            !((~*(const uint32_t *)(buf + i) &
 | 
	
		
			
				|  |  | -++                    (*(const uint32_t *)(buf + i) - 0x01010101U)) &
 | 
	
		
			
				|  |  | -++                    0x80808080U))
 | 
	
		
			
				|  |  | -++        i += 4;
 | 
	
		
			
				|  |  | -++#endif
 | 
	
		
			
				|  |  | -++#endif
 | 
	
		
			
				|  |  | -++    for (; i < size; i++)
 | 
	
		
			
				|  |  | -++        if (!buf[i])
 | 
	
		
			
				|  |  | -++            break;
 | 
	
		
			
				|  |  | -++    return i;
 | 
	
		
			
				|  |  | -++}
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -+ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
 | 
	
		
			
				|  |  | -+                              const int chroma_format_idc)
 | 
	
		
			
				|  |  | -+ {
 | 
	
		
			
				|  |  | -+@@ -133,6 +161,7 @@ av_cold void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
 | 
	
		
			
				|  |  | -+         H264_DSP(8);
 | 
	
		
			
				|  |  | -+         break;
 | 
	
		
			
				|  |  | -+     }
 | 
	
		
			
				|  |  | -++    c->h264_find_start_code_candidate = h264_find_start_code_candidate_c;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+     if (ARCH_ARM) ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | -+     if (ARCH_PPC) ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | -+diff --git a/libavcodec/h264dsp.h b/libavcodec/h264dsp.h
 | 
	
		
			
				|  |  | -+index 1f9f8fe..6249ba7 100644
 | 
	
		
			
				|  |  | -+--- a/libavcodec/h264dsp.h
 | 
	
		
			
				|  |  | -++++ b/libavcodec/h264dsp.h
 | 
	
		
			
				|  |  | -+@@ -105,6 +105,15 @@ typedef struct H264DSPContext {
 | 
	
		
			
				|  |  | -+     /* bypass-transform */
 | 
	
		
			
				|  |  | -+     void (*h264_add_pixels8_clear)(uint8_t *dst, int16_t *block, int stride);
 | 
	
		
			
				|  |  | -+     void (*h264_add_pixels4_clear)(uint8_t *dst, int16_t *block, int stride);
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++    /**
 | 
	
		
			
				|  |  | -++     * Search buf from the start for up to size bytes. Return the index
 | 
	
		
			
				|  |  | -++     * of a zero byte, or >= size if not found. Ideally, use lookahead
 | 
	
		
			
				|  |  | -++     * to filter out any zero bytes that are known to not be followed by
 | 
	
		
			
				|  |  | -++     * one or more further zero bytes and a one byte. Better still, filter
 | 
	
		
			
				|  |  | -++     * out any bytes that form the trailing_zero_8bits syntax element too.
 | 
	
		
			
				|  |  | -++     */
 | 
	
		
			
				|  |  | -++    int (*h264_find_start_code_candidate)(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | -+ } H264DSPContext;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ void ff_h264dsp_init(H264DSPContext *c, const int bit_depth,
 | 
	
		
			
				|  |  | -+--
 | 
	
		
			
				|  |  | -+1.7.9.5
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch b/lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..cdc2d1e
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/patches/0058-arm-Add-assembly-version-of-h264_find_start_code_can.patch
 | 
	
		
			
				|  |  | -@@ -0,0 +1,322 @@
 | 
	
		
			
				|  |  | -+From 45e10e5c8d3df09c80a4d80483bff2712367f3fa Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -+From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -+Date: Mon, 5 Aug 2013 13:12:48 +0100
 | 
	
		
			
				|  |  | -+Subject: [PATCH 3/3] arm: Add assembly version of
 | 
	
		
			
				|  |  | -+ h264_find_start_code_candidate
 | 
	
		
			
				|  |  | -+MIME-Version: 1.0
 | 
	
		
			
				|  |  | -+Content-Type: text/plain; charset=UTF-8
 | 
	
		
			
				|  |  | -+Content-Transfer-Encoding: 8bit
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+               Before          After
 | 
	
		
			
				|  |  | -+               Mean   StdDev   Mean   StdDev  Change
 | 
	
		
			
				|  |  | -+This function   508.8 23.4      185.4  9.0    +174.4%
 | 
	
		
			
				|  |  | -+Overall        3068.5 31.7     2752.1 29.4     +11.5%
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+In combination with the preceding patch:
 | 
	
		
			
				|  |  | -+                Before          After
 | 
	
		
			
				|  |  | -+                Mean   StdDev   Mean   StdDev  Change
 | 
	
		
			
				|  |  | -+Overall         2925.6 26.2     2752.1 29.4     +6.3%
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+Signed-off-by: Martin Storsjö <martin@martin.st>
 | 
	
		
			
				|  |  | -+---
 | 
	
		
			
				|  |  | -+ libavcodec/arm/Makefile           |    1 +
 | 
	
		
			
				|  |  | -+ libavcodec/arm/h264dsp_armv6.S    |  253 +++++++++++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | -+ libavcodec/arm/h264dsp_init_arm.c |    4 +
 | 
	
		
			
				|  |  | -+ 3 files changed, 258 insertions(+)
 | 
	
		
			
				|  |  | -+ create mode 100644 libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+diff --git a/libavcodec/arm/Makefile b/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -+index e941aaa..9c64b36 100644
 | 
	
		
			
				|  |  | -+--- a/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -++++ b/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -+@@ -45,6 +45,7 @@ ARMV6-OBJS-$(CONFIG_DSPUTIL)           += arm/dsputil_init_armv6.o      \
 | 
	
		
			
				|  |  | -+                                           arm/simple_idct_armv6.o       \
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ ARMV6-OBJS-$(CONFIG_AC3DSP)            += arm/ac3dsp_armv6.o
 | 
	
		
			
				|  |  | -++ARMV6-OBJS-$(CONFIG_H264DSP)           += arm/h264dsp_armv6.o
 | 
	
		
			
				|  |  | -+ ARMV6-OBJS-$(CONFIG_HPELDSP)           += arm/hpeldsp_init_armv6.o      \
 | 
	
		
			
				|  |  | -+                                           arm/hpeldsp_armv6.o
 | 
	
		
			
				|  |  | -+ ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP)      += arm/mpegaudiodsp_fixed_armv6.o
 | 
	
		
			
				|  |  | -+diff --git a/libavcodec/arm/h264dsp_armv6.S b/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -+new file mode 100644
 | 
	
		
			
				|  |  | -+index 0000000..c4f12a6
 | 
	
		
			
				|  |  | -+--- /dev/null
 | 
	
		
			
				|  |  | -++++ b/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -+@@ -0,0 +1,253 @@
 | 
	
		
			
				|  |  | -++/*
 | 
	
		
			
				|  |  | -++ * Copyright (c) 2013 RISC OS Open Ltd
 | 
	
		
			
				|  |  | -++ * Author: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -++ *
 | 
	
		
			
				|  |  | -++ * This file is part of Libav.
 | 
	
		
			
				|  |  | -++ *
 | 
	
		
			
				|  |  | -++ * Libav 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.
 | 
	
		
			
				|  |  | -++ *
 | 
	
		
			
				|  |  | -++ * Libav 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 Libav; if not, write to the Free Software
 | 
	
		
			
				|  |  | -++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
	
		
			
				|  |  | -++ */
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++#include "libavutil/arm/asm.S"
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++RESULT  .req    a1
 | 
	
		
			
				|  |  | -++BUF     .req    a1
 | 
	
		
			
				|  |  | -++SIZE    .req    a2
 | 
	
		
			
				|  |  | -++PATTERN .req    a3
 | 
	
		
			
				|  |  | -++PTR     .req    a4
 | 
	
		
			
				|  |  | -++DAT0    .req    v1
 | 
	
		
			
				|  |  | -++DAT1    .req    v2
 | 
	
		
			
				|  |  | -++DAT2    .req    v3
 | 
	
		
			
				|  |  | -++DAT3    .req    v4
 | 
	
		
			
				|  |  | -++TMP0    .req    v5
 | 
	
		
			
				|  |  | -++TMP1    .req    v6
 | 
	
		
			
				|  |  | -++TMP2    .req    ip
 | 
	
		
			
				|  |  | -++TMP3    .req    lr
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++#define PRELOAD_DISTANCE 4
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++.macro innerloop4
 | 
	
		
			
				|  |  | -++        ldr     DAT0, [PTR], #4
 | 
	
		
			
				|  |  | -++        subs    SIZE, SIZE, #4 @ C flag survives rest of macro
 | 
	
		
			
				|  |  | -++        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -++        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -++        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | -++.endm
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++.macro innerloop16  decrement, do_preload
 | 
	
		
			
				|  |  | -++        ldmia   PTR!, {DAT0,DAT1,DAT2,DAT3}
 | 
	
		
			
				|  |  | -++ .ifnc "\do_preload",""
 | 
	
		
			
				|  |  | -++        pld     [PTR, #PRELOAD_DISTANCE*32]
 | 
	
		
			
				|  |  | -++ .endif
 | 
	
		
			
				|  |  | -++ .ifnc "\decrement",""
 | 
	
		
			
				|  |  | -++        subs    SIZE, SIZE, #\decrement @ C flag survives rest of macro
 | 
	
		
			
				|  |  | -++ .endif
 | 
	
		
			
				|  |  | -++        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -++        sub     TMP1, DAT1, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -++        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -++        bic     TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | -++        sub     TMP2, DAT2, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -++        sub     TMP3, DAT3, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -++        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | -++        bic     TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | -++        it      eq
 | 
	
		
			
				|  |  | -++        andseq  TMP1, TMP1, PATTERN
 | 
	
		
			
				|  |  | -++        bic     TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | -++        itt     eq
 | 
	
		
			
				|  |  | -++        andseq  TMP2, TMP2, PATTERN
 | 
	
		
			
				|  |  | -++        andseq  TMP3, TMP3, PATTERN
 | 
	
		
			
				|  |  | -++.endm
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++/* int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size) */
 | 
	
		
			
				|  |  | -++function ff_h264_find_start_code_candidate_armv6, export=1
 | 
	
		
			
				|  |  | -++        push    {v1-v6,lr}
 | 
	
		
			
				|  |  | -++        mov     PTR, BUF
 | 
	
		
			
				|  |  | -++        @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
 | 
	
		
			
				|  |  | -++        @ before using code that does preloads
 | 
	
		
			
				|  |  | -++        cmp     SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
 | 
	
		
			
				|  |  | -++        blo     60f
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++        @ Get to word-alignment, 1 byte at a time
 | 
	
		
			
				|  |  | -++        tst     PTR, #3
 | 
	
		
			
				|  |  | -++        beq     2f
 | 
	
		
			
				|  |  | -++1:      ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -++        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -++        teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        beq     90f
 | 
	
		
			
				|  |  | -++        tst     PTR, #3
 | 
	
		
			
				|  |  | -++        bne     1b
 | 
	
		
			
				|  |  | -++2:      @ Get to 4-word alignment, 1 word at a time
 | 
	
		
			
				|  |  | -++        ldr     PATTERN, =0x80008000
 | 
	
		
			
				|  |  | -++        setend  be
 | 
	
		
			
				|  |  | -++        tst     PTR, #12
 | 
	
		
			
				|  |  | -++        beq     4f
 | 
	
		
			
				|  |  | -++3:      innerloop4
 | 
	
		
			
				|  |  | -++        bne     91f
 | 
	
		
			
				|  |  | -++        tst     PTR, #12
 | 
	
		
			
				|  |  | -++        bne     3b
 | 
	
		
			
				|  |  | -++4:      @ Get to cacheline (8-word) alignment
 | 
	
		
			
				|  |  | -++        tst     PTR, #16
 | 
	
		
			
				|  |  | -++        beq     5f
 | 
	
		
			
				|  |  | -++        innerloop16  16
 | 
	
		
			
				|  |  | -++        bne     93f
 | 
	
		
			
				|  |  | -++5:      @ Check complete cachelines, with preloading
 | 
	
		
			
				|  |  | -++        @ We need to stop when there are still (PRELOAD_DISTANCE+1)
 | 
	
		
			
				|  |  | -++        @ complete cachelines to go
 | 
	
		
			
				|  |  | -++        sub     SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
 | 
	
		
			
				|  |  | -++6:      innerloop16  , do_preload
 | 
	
		
			
				|  |  | -++        bne     93f
 | 
	
		
			
				|  |  | -++        innerloop16  32
 | 
	
		
			
				|  |  | -++        bne     93f
 | 
	
		
			
				|  |  | -++        bcs     6b
 | 
	
		
			
				|  |  | -++        @ Preload trailing part-cacheline, if any
 | 
	
		
			
				|  |  | -++        tst     SIZE, #31
 | 
	
		
			
				|  |  | -++        beq     7f
 | 
	
		
			
				|  |  | -++        pld     [PTR, #(PRELOAD_DISTANCE+1)*32]
 | 
	
		
			
				|  |  | -++        @ Check remaining data without doing any more preloads. First
 | 
	
		
			
				|  |  | -++        @ do in chunks of 4 words:
 | 
	
		
			
				|  |  | -++7:      adds    SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
 | 
	
		
			
				|  |  | -++        bmi     9f
 | 
	
		
			
				|  |  | -++8:      innerloop16  16
 | 
	
		
			
				|  |  | -++        bne     93f
 | 
	
		
			
				|  |  | -++        bcs     8b
 | 
	
		
			
				|  |  | -++        @ Then in words:
 | 
	
		
			
				|  |  | -++9:      adds    SIZE, SIZE, #16 - 4
 | 
	
		
			
				|  |  | -++        bmi     11f
 | 
	
		
			
				|  |  | -++10:     innerloop4
 | 
	
		
			
				|  |  | -++        bne     91f
 | 
	
		
			
				|  |  | -++        bcs     10b
 | 
	
		
			
				|  |  | -++11:     setend  le
 | 
	
		
			
				|  |  | -++        @ Check second byte of final halfword
 | 
	
		
			
				|  |  | -++        ldrb    DAT0, [PTR, #-1]
 | 
	
		
			
				|  |  | -++        teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        beq     90f
 | 
	
		
			
				|  |  | -++        @ Check any remaining bytes
 | 
	
		
			
				|  |  | -++        tst     SIZE, #3
 | 
	
		
			
				|  |  | -++        beq     13f
 | 
	
		
			
				|  |  | -++12:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -++        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -++        teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        beq     90f
 | 
	
		
			
				|  |  | -++        tst     SIZE, #3
 | 
	
		
			
				|  |  | -++        bne     12b
 | 
	
		
			
				|  |  | -++        @ No candidate found
 | 
	
		
			
				|  |  | -++13:     sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -++        b       99f
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++60:     @ Small buffer - simply check by looping over bytes
 | 
	
		
			
				|  |  | -++        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -++        bcc     99f
 | 
	
		
			
				|  |  | -++61:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -++        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -++        teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        beq     90f
 | 
	
		
			
				|  |  | -++        bcs     61b
 | 
	
		
			
				|  |  | -++        @ No candidate found
 | 
	
		
			
				|  |  | -++        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -++        b       99f
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++90:     @ Found a candidate at the preceding byte
 | 
	
		
			
				|  |  | -++        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -++        sub     RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -++        b       99f
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++91:     @ Found a candidate somewhere in the preceding 4 bytes
 | 
	
		
			
				|  |  | -++        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -++        sub     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -++        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | -++        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -++        itt     pl
 | 
	
		
			
				|  |  | -++        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | -++        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -++        bpl     92f
 | 
	
		
			
				|  |  | -++        teq     RESULT, #0
 | 
	
		
			
				|  |  | -++        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | -++        ldrb    DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | -++92:     teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        it      eq
 | 
	
		
			
				|  |  | -++        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -++        b       98f
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++93:     @ Found a candidate somewhere in the preceding 16 bytes
 | 
	
		
			
				|  |  | -++        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -++        sub     RESULT, RESULT, #16
 | 
	
		
			
				|  |  | -++        teq     TMP0, #0
 | 
	
		
			
				|  |  | -++        beq     95f @ not in first 4 bytes
 | 
	
		
			
				|  |  | -++        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | -++        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -++        itt     pl
 | 
	
		
			
				|  |  | -++        ldrbpl  DAT0, [PTR, #-15]
 | 
	
		
			
				|  |  | -++        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -++        bpl     94f
 | 
	
		
			
				|  |  | -++        teq     RESULT, #0
 | 
	
		
			
				|  |  | -++        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | -++        ldrb    DAT0, [PTR, #-17]
 | 
	
		
			
				|  |  | -++94:     teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        it      eq
 | 
	
		
			
				|  |  | -++        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -++        b       98f
 | 
	
		
			
				|  |  | -++95:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -++        teq     TMP1, #0
 | 
	
		
			
				|  |  | -++        beq     96f @ not in next 4 bytes
 | 
	
		
			
				|  |  | -++        sub     TMP1, DAT1, #0x20000
 | 
	
		
			
				|  |  | -++        bics    TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | -++        itee    mi
 | 
	
		
			
				|  |  | -++        ldrbmi  DAT0, [PTR, #-13]
 | 
	
		
			
				|  |  | -++        ldrbpl  DAT0, [PTR, #-11]
 | 
	
		
			
				|  |  | -++        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -++        teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        it      eq
 | 
	
		
			
				|  |  | -++        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -++        b       98f
 | 
	
		
			
				|  |  | -++96:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -++        teq     TMP2, #0
 | 
	
		
			
				|  |  | -++        beq     97f @ not in next 4 bytes
 | 
	
		
			
				|  |  | -++        sub     TMP2, DAT2, #0x20000
 | 
	
		
			
				|  |  | -++        bics    TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | -++        itee    mi
 | 
	
		
			
				|  |  | -++        ldrbmi  DAT0, [PTR, #-9]
 | 
	
		
			
				|  |  | -++        ldrbpl  DAT0, [PTR, #-7]
 | 
	
		
			
				|  |  | -++        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -++        teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        it      eq
 | 
	
		
			
				|  |  | -++        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -++        b       98f
 | 
	
		
			
				|  |  | -++97:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -++        sub     TMP3, DAT3, #0x20000
 | 
	
		
			
				|  |  | -++        bics    TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | -++        itee    mi
 | 
	
		
			
				|  |  | -++        ldrbmi  DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | -++        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | -++        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -++        teq     DAT0, #0
 | 
	
		
			
				|  |  | -++        it      eq
 | 
	
		
			
				|  |  | -++        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -++        @ drop through to 98f
 | 
	
		
			
				|  |  | -++98:     setend  le
 | 
	
		
			
				|  |  | -++99:     pop     {v1-v6,pc}
 | 
	
		
			
				|  |  | -++.endfunc
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -++        .unreq  RESULT
 | 
	
		
			
				|  |  | -++        .unreq  BUF
 | 
	
		
			
				|  |  | -++        .unreq  SIZE
 | 
	
		
			
				|  |  | -++        .unreq  PATTERN
 | 
	
		
			
				|  |  | -++        .unreq  PTR
 | 
	
		
			
				|  |  | -++        .unreq  DAT0
 | 
	
		
			
				|  |  | -++        .unreq  DAT1
 | 
	
		
			
				|  |  | -++        .unreq  DAT2
 | 
	
		
			
				|  |  | -++        .unreq  DAT3
 | 
	
		
			
				|  |  | -++        .unreq  TMP0
 | 
	
		
			
				|  |  | -++        .unreq  TMP1
 | 
	
		
			
				|  |  | -++        .unreq  TMP2
 | 
	
		
			
				|  |  | -++        .unreq  TMP3
 | 
	
		
			
				|  |  | -+diff --git a/libavcodec/arm/h264dsp_init_arm.c b/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -+index bb8b3b9..b206a1b 100644
 | 
	
		
			
				|  |  | -+--- a/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -++++ b/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -+@@ -24,6 +24,8 @@
 | 
	
		
			
				|  |  | -+ #include "libavutil/arm/cpu.h"
 | 
	
		
			
				|  |  | -+ #include "libavcodec/h264dsp.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -++int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | -++
 | 
	
		
			
				|  |  | -+ void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
 | 
	
		
			
				|  |  | -+                                      int beta, int8_t *tc0);
 | 
	
		
			
				|  |  | -+ void ff_h264_h_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
 | 
	
		
			
				|  |  | -+@@ -102,6 +104,8 @@ av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
 | 
	
		
			
				|  |  | -+ {
 | 
	
		
			
				|  |  | -+     int cpu_flags = av_get_cpu_flags();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -++    if (have_armv6(cpu_flags))
 | 
	
		
			
				|  |  | -++        c->h264_find_start_code_candidate = ff_h264_find_start_code_candidate_armv6;
 | 
	
		
			
				|  |  | -+     if (have_neon(cpu_flags))
 | 
	
		
			
				|  |  | -+         h264dsp_init_neon(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | -+ }
 | 
	
		
			
				|  |  | -+--
 | 
	
		
			
				|  |  | -+1.7.9.5
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From db098a580259625bb7b7385a48cb0756aea5cafe Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 16 Apr 2014 01:51:31 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 05/94] h264: Move search code search functions into separate
 | 
	
		
			
				|  |  | - source files.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This permits re-use with parsers for codecs which use similar start codes.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/Makefile               |   2 +-
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/Makefile           |   2 +-
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S    | 253 ---------------------------
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c |   4 +-
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/startcode_armv6.S  | 253 +++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/h264dsp.c              |  31 +---
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/startcode.c            |  57 ++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/startcode.h            |  35 ++++
 | 
	
		
			
				|  |  | - 8 files changed, 351 insertions(+), 286 deletions(-)
 | 
	
		
			
				|  |  | - delete mode 100644 lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/libavcodec/arm/startcode_armv6.S
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/libavcodec/startcode.c
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/libavcodec/startcode.h
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/Makefile b/lib/ffmpeg/libavcodec/Makefile
 | 
	
		
			
				|  |  | -index dc065a5..460f42c 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/Makefile
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/Makefile
 | 
	
		
			
				|  |  | -@@ -49,7 +49,7 @@ OBJS-$(CONFIG_FFT)                     += avfft.o fft_fixed.o fft_float.o \
 | 
	
		
			
				|  |  | -                                           $(FFT-OBJS-yes)
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_GOLOMB)                  += golomb.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_H264CHROMA)              += h264chroma.o
 | 
	
		
			
				|  |  | --OBJS-$(CONFIG_H264DSP)                 += h264dsp.o h264idct.o
 | 
	
		
			
				|  |  | -+OBJS-$(CONFIG_H264DSP)                 += h264dsp.o h264idct.o startcode.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_H264PRED)                += h264pred.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_H264QPEL)                += h264qpel.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_HUFFMAN)                 += huffman.o
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -index 480000b71..0b432e3 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -@@ -9,7 +9,7 @@ OBJS-$(CONFIG_AAC_DECODER)             += arm/sbrdsp_init_arm.o         \
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_DCA_DECODER)             += arm/dcadsp_init_arm.o         \
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - ARMV6-OBJS-$(CONFIG_AC3DSP)            += arm/ac3dsp_armv6.o
 | 
	
		
			
				|  |  | --ARMV6-OBJS-$(CONFIG_H264DSP)           += arm/h264dsp_armv6.o
 | 
	
		
			
				|  |  | -+ARMV6-OBJS-$(CONFIG_H264DSP)           += arm/startcode_armv6.o
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_FLAC_DECODER)            += arm/flacdsp_init_arm.o        \
 | 
	
		
			
				|  |  | -                                           arm/flacdsp_arm.o             \
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S b/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -deleted file mode 100644
 | 
	
		
			
				|  |  | -index c4f12a6..0000000
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/h264dsp_armv6.S
 | 
	
		
			
				|  |  | -+++ /dev/null
 | 
	
		
			
				|  |  | -@@ -1,253 +0,0 @@
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | -- * Copyright (c) 2013 RISC OS Open Ltd
 | 
	
		
			
				|  |  | -- * Author: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- * This file is part of Libav.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- * Libav 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.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- * Libav 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 Libav; if not, write to the Free Software
 | 
	
		
			
				|  |  | -- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
	
		
			
				|  |  | -- */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#include "libavutil/arm/asm.S"
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --RESULT  .req    a1
 | 
	
		
			
				|  |  | --BUF     .req    a1
 | 
	
		
			
				|  |  | --SIZE    .req    a2
 | 
	
		
			
				|  |  | --PATTERN .req    a3
 | 
	
		
			
				|  |  | --PTR     .req    a4
 | 
	
		
			
				|  |  | --DAT0    .req    v1
 | 
	
		
			
				|  |  | --DAT1    .req    v2
 | 
	
		
			
				|  |  | --DAT2    .req    v3
 | 
	
		
			
				|  |  | --DAT3    .req    v4
 | 
	
		
			
				|  |  | --TMP0    .req    v5
 | 
	
		
			
				|  |  | --TMP1    .req    v6
 | 
	
		
			
				|  |  | --TMP2    .req    ip
 | 
	
		
			
				|  |  | --TMP3    .req    lr
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#define PRELOAD_DISTANCE 4
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --.macro innerloop4
 | 
	
		
			
				|  |  | --        ldr     DAT0, [PTR], #4
 | 
	
		
			
				|  |  | --        subs    SIZE, SIZE, #4 @ C flag survives rest of macro
 | 
	
		
			
				|  |  | --        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | --        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | --        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | --.endm
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --.macro innerloop16  decrement, do_preload
 | 
	
		
			
				|  |  | --        ldmia   PTR!, {DAT0,DAT1,DAT2,DAT3}
 | 
	
		
			
				|  |  | -- .ifnc "\do_preload",""
 | 
	
		
			
				|  |  | --        pld     [PTR, #PRELOAD_DISTANCE*32]
 | 
	
		
			
				|  |  | -- .endif
 | 
	
		
			
				|  |  | -- .ifnc "\decrement",""
 | 
	
		
			
				|  |  | --        subs    SIZE, SIZE, #\decrement @ C flag survives rest of macro
 | 
	
		
			
				|  |  | -- .endif
 | 
	
		
			
				|  |  | --        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | --        sub     TMP1, DAT1, PATTERN, lsr #14
 | 
	
		
			
				|  |  | --        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | --        bic     TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | --        sub     TMP2, DAT2, PATTERN, lsr #14
 | 
	
		
			
				|  |  | --        sub     TMP3, DAT3, PATTERN, lsr #14
 | 
	
		
			
				|  |  | --        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | --        bic     TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | --        it      eq
 | 
	
		
			
				|  |  | --        andseq  TMP1, TMP1, PATTERN
 | 
	
		
			
				|  |  | --        bic     TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | --        itt     eq
 | 
	
		
			
				|  |  | --        andseq  TMP2, TMP2, PATTERN
 | 
	
		
			
				|  |  | --        andseq  TMP3, TMP3, PATTERN
 | 
	
		
			
				|  |  | --.endm
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/* int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size) */
 | 
	
		
			
				|  |  | --function ff_h264_find_start_code_candidate_armv6, export=1
 | 
	
		
			
				|  |  | --        push    {v1-v6,lr}
 | 
	
		
			
				|  |  | --        mov     PTR, BUF
 | 
	
		
			
				|  |  | --        @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
 | 
	
		
			
				|  |  | --        @ before using code that does preloads
 | 
	
		
			
				|  |  | --        cmp     SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
 | 
	
		
			
				|  |  | --        blo     60f
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --        @ Get to word-alignment, 1 byte at a time
 | 
	
		
			
				|  |  | --        tst     PTR, #3
 | 
	
		
			
				|  |  | --        beq     2f
 | 
	
		
			
				|  |  | --1:      ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | --        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | --        teq     DAT0, #0
 | 
	
		
			
				|  |  | --        beq     90f
 | 
	
		
			
				|  |  | --        tst     PTR, #3
 | 
	
		
			
				|  |  | --        bne     1b
 | 
	
		
			
				|  |  | --2:      @ Get to 4-word alignment, 1 word at a time
 | 
	
		
			
				|  |  | --        ldr     PATTERN, =0x80008000
 | 
	
		
			
				|  |  | --        setend  be
 | 
	
		
			
				|  |  | --        tst     PTR, #12
 | 
	
		
			
				|  |  | --        beq     4f
 | 
	
		
			
				|  |  | --3:      innerloop4
 | 
	
		
			
				|  |  | --        bne     91f
 | 
	
		
			
				|  |  | --        tst     PTR, #12
 | 
	
		
			
				|  |  | --        bne     3b
 | 
	
		
			
				|  |  | --4:      @ Get to cacheline (8-word) alignment
 | 
	
		
			
				|  |  | --        tst     PTR, #16
 | 
	
		
			
				|  |  | --        beq     5f
 | 
	
		
			
				|  |  | --        innerloop16  16
 | 
	
		
			
				|  |  | --        bne     93f
 | 
	
		
			
				|  |  | --5:      @ Check complete cachelines, with preloading
 | 
	
		
			
				|  |  | --        @ We need to stop when there are still (PRELOAD_DISTANCE+1)
 | 
	
		
			
				|  |  | --        @ complete cachelines to go
 | 
	
		
			
				|  |  | --        sub     SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
 | 
	
		
			
				|  |  | --6:      innerloop16  , do_preload
 | 
	
		
			
				|  |  | --        bne     93f
 | 
	
		
			
				|  |  | --        innerloop16  32
 | 
	
		
			
				|  |  | --        bne     93f
 | 
	
		
			
				|  |  | --        bcs     6b
 | 
	
		
			
				|  |  | --        @ Preload trailing part-cacheline, if any
 | 
	
		
			
				|  |  | --        tst     SIZE, #31
 | 
	
		
			
				|  |  | --        beq     7f
 | 
	
		
			
				|  |  | --        pld     [PTR, #(PRELOAD_DISTANCE+1)*32]
 | 
	
		
			
				|  |  | --        @ Check remaining data without doing any more preloads. First
 | 
	
		
			
				|  |  | --        @ do in chunks of 4 words:
 | 
	
		
			
				|  |  | --7:      adds    SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
 | 
	
		
			
				|  |  | --        bmi     9f
 | 
	
		
			
				|  |  | --8:      innerloop16  16
 | 
	
		
			
				|  |  | --        bne     93f
 | 
	
		
			
				|  |  | --        bcs     8b
 | 
	
		
			
				|  |  | --        @ Then in words:
 | 
	
		
			
				|  |  | --9:      adds    SIZE, SIZE, #16 - 4
 | 
	
		
			
				|  |  | --        bmi     11f
 | 
	
		
			
				|  |  | --10:     innerloop4
 | 
	
		
			
				|  |  | --        bne     91f
 | 
	
		
			
				|  |  | --        bcs     10b
 | 
	
		
			
				|  |  | --11:     setend  le
 | 
	
		
			
				|  |  | --        @ Check second byte of final halfword
 | 
	
		
			
				|  |  | --        ldrb    DAT0, [PTR, #-1]
 | 
	
		
			
				|  |  | --        teq     DAT0, #0
 | 
	
		
			
				|  |  | --        beq     90f
 | 
	
		
			
				|  |  | --        @ Check any remaining bytes
 | 
	
		
			
				|  |  | --        tst     SIZE, #3
 | 
	
		
			
				|  |  | --        beq     13f
 | 
	
		
			
				|  |  | --12:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | --        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | --        teq     DAT0, #0
 | 
	
		
			
				|  |  | --        beq     90f
 | 
	
		
			
				|  |  | --        tst     SIZE, #3
 | 
	
		
			
				|  |  | --        bne     12b
 | 
	
		
			
				|  |  | --        @ No candidate found
 | 
	
		
			
				|  |  | --13:     sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | --        b       99f
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --60:     @ Small buffer - simply check by looping over bytes
 | 
	
		
			
				|  |  | --        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | --        bcc     99f
 | 
	
		
			
				|  |  | --61:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | --        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | --        teq     DAT0, #0
 | 
	
		
			
				|  |  | --        beq     90f
 | 
	
		
			
				|  |  | --        bcs     61b
 | 
	
		
			
				|  |  | --        @ No candidate found
 | 
	
		
			
				|  |  | --        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | --        b       99f
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --90:     @ Found a candidate at the preceding byte
 | 
	
		
			
				|  |  | --        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | --        sub     RESULT, RESULT, #1
 | 
	
		
			
				|  |  | --        b       99f
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --91:     @ Found a candidate somewhere in the preceding 4 bytes
 | 
	
		
			
				|  |  | --        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | --        sub     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | --        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | --        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | --        itt     pl
 | 
	
		
			
				|  |  | --        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | --        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | --        bpl     92f
 | 
	
		
			
				|  |  | --        teq     RESULT, #0
 | 
	
		
			
				|  |  | --        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | --        ldrb    DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | --92:     teq     DAT0, #0
 | 
	
		
			
				|  |  | --        it      eq
 | 
	
		
			
				|  |  | --        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | --        b       98f
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --93:     @ Found a candidate somewhere in the preceding 16 bytes
 | 
	
		
			
				|  |  | --        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | --        sub     RESULT, RESULT, #16
 | 
	
		
			
				|  |  | --        teq     TMP0, #0
 | 
	
		
			
				|  |  | --        beq     95f @ not in first 4 bytes
 | 
	
		
			
				|  |  | --        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | --        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | --        itt     pl
 | 
	
		
			
				|  |  | --        ldrbpl  DAT0, [PTR, #-15]
 | 
	
		
			
				|  |  | --        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | --        bpl     94f
 | 
	
		
			
				|  |  | --        teq     RESULT, #0
 | 
	
		
			
				|  |  | --        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | --        ldrb    DAT0, [PTR, #-17]
 | 
	
		
			
				|  |  | --94:     teq     DAT0, #0
 | 
	
		
			
				|  |  | --        it      eq
 | 
	
		
			
				|  |  | --        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | --        b       98f
 | 
	
		
			
				|  |  | --95:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | --        teq     TMP1, #0
 | 
	
		
			
				|  |  | --        beq     96f @ not in next 4 bytes
 | 
	
		
			
				|  |  | --        sub     TMP1, DAT1, #0x20000
 | 
	
		
			
				|  |  | --        bics    TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | --        itee    mi
 | 
	
		
			
				|  |  | --        ldrbmi  DAT0, [PTR, #-13]
 | 
	
		
			
				|  |  | --        ldrbpl  DAT0, [PTR, #-11]
 | 
	
		
			
				|  |  | --        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | --        teq     DAT0, #0
 | 
	
		
			
				|  |  | --        it      eq
 | 
	
		
			
				|  |  | --        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | --        b       98f
 | 
	
		
			
				|  |  | --96:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | --        teq     TMP2, #0
 | 
	
		
			
				|  |  | --        beq     97f @ not in next 4 bytes
 | 
	
		
			
				|  |  | --        sub     TMP2, DAT2, #0x20000
 | 
	
		
			
				|  |  | --        bics    TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | --        itee    mi
 | 
	
		
			
				|  |  | --        ldrbmi  DAT0, [PTR, #-9]
 | 
	
		
			
				|  |  | --        ldrbpl  DAT0, [PTR, #-7]
 | 
	
		
			
				|  |  | --        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | --        teq     DAT0, #0
 | 
	
		
			
				|  |  | --        it      eq
 | 
	
		
			
				|  |  | --        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | --        b       98f
 | 
	
		
			
				|  |  | --97:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | --        sub     TMP3, DAT3, #0x20000
 | 
	
		
			
				|  |  | --        bics    TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | --        itee    mi
 | 
	
		
			
				|  |  | --        ldrbmi  DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | --        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | --        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | --        teq     DAT0, #0
 | 
	
		
			
				|  |  | --        it      eq
 | 
	
		
			
				|  |  | --        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | --        @ drop through to 98f
 | 
	
		
			
				|  |  | --98:     setend  le
 | 
	
		
			
				|  |  | --99:     pop     {v1-v6,pc}
 | 
	
		
			
				|  |  | --.endfunc
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --        .unreq  RESULT
 | 
	
		
			
				|  |  | --        .unreq  BUF
 | 
	
		
			
				|  |  | --        .unreq  SIZE
 | 
	
		
			
				|  |  | --        .unreq  PATTERN
 | 
	
		
			
				|  |  | --        .unreq  PTR
 | 
	
		
			
				|  |  | --        .unreq  DAT0
 | 
	
		
			
				|  |  | --        .unreq  DAT1
 | 
	
		
			
				|  |  | --        .unreq  DAT2
 | 
	
		
			
				|  |  | --        .unreq  DAT3
 | 
	
		
			
				|  |  | --        .unreq  TMP0
 | 
	
		
			
				|  |  | --        .unreq  TMP1
 | 
	
		
			
				|  |  | --        .unreq  TMP2
 | 
	
		
			
				|  |  | --        .unreq  TMP3
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -index 2804e56..842fb9f 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/h264dsp_init_arm.c
 | 
	
		
			
				|  |  | -@@ -24,7 +24,7 @@
 | 
	
		
			
				|  |  | - #include "libavutil/arm/cpu.h"
 | 
	
		
			
				|  |  | - #include "libavcodec/h264dsp.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --int ff_h264_find_start_code_candidate_armv6(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | -+int ff_startcode_find_candidate_armv6(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void ff_h264_v_loop_filter_luma_neon(uint8_t *pix, int stride, int alpha,
 | 
	
		
			
				|  |  | -                                      int beta, int8_t *tc0);
 | 
	
		
			
				|  |  | -@@ -109,7 +109,7 @@ av_cold void ff_h264dsp_init_arm(H264DSPContext *c, const int bit_depth,
 | 
	
		
			
				|  |  | -     int cpu_flags = av_get_cpu_flags();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (have_armv6(cpu_flags))
 | 
	
		
			
				|  |  | --        c->h264_find_start_code_candidate = ff_h264_find_start_code_candidate_armv6;
 | 
	
		
			
				|  |  | -+        c->h264_find_start_code_candidate = ff_startcode_find_candidate_armv6;
 | 
	
		
			
				|  |  | -     if (have_neon(cpu_flags))
 | 
	
		
			
				|  |  | -         ff_h264dsp_init_neon(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/startcode_armv6.S b/lib/ffmpeg/libavcodec/arm/startcode_armv6.S
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..a46f009
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/startcode_armv6.S
 | 
	
		
			
				|  |  | -@@ -0,0 +1,253 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ * Copyright (c) 2013 RISC OS Open Ltd
 | 
	
		
			
				|  |  | -+ * Author: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * 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"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+RESULT  .req    a1
 | 
	
		
			
				|  |  | -+BUF     .req    a1
 | 
	
		
			
				|  |  | -+SIZE    .req    a2
 | 
	
		
			
				|  |  | -+PATTERN .req    a3
 | 
	
		
			
				|  |  | -+PTR     .req    a4
 | 
	
		
			
				|  |  | -+DAT0    .req    v1
 | 
	
		
			
				|  |  | -+DAT1    .req    v2
 | 
	
		
			
				|  |  | -+DAT2    .req    v3
 | 
	
		
			
				|  |  | -+DAT3    .req    v4
 | 
	
		
			
				|  |  | -+TMP0    .req    v5
 | 
	
		
			
				|  |  | -+TMP1    .req    v6
 | 
	
		
			
				|  |  | -+TMP2    .req    ip
 | 
	
		
			
				|  |  | -+TMP3    .req    lr
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define PRELOAD_DISTANCE 4
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro innerloop4
 | 
	
		
			
				|  |  | -+        ldr     DAT0, [PTR], #4
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #4 @ C flag survives rest of macro
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro innerloop16  decrement, do_preload
 | 
	
		
			
				|  |  | -+        ldmia   PTR!, {DAT0,DAT1,DAT2,DAT3}
 | 
	
		
			
				|  |  | -+ .ifnc "\do_preload",""
 | 
	
		
			
				|  |  | -+        pld     [PTR, #PRELOAD_DISTANCE*32]
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .ifnc "\decrement",""
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #\decrement @ C flag survives rest of macro
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        sub     TMP1, DAT1, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        bic     TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        bic     TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | -+        sub     TMP2, DAT2, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        sub     TMP3, DAT3, PATTERN, lsr #14
 | 
	
		
			
				|  |  | -+        ands    TMP0, TMP0, PATTERN
 | 
	
		
			
				|  |  | -+        bic     TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        andseq  TMP1, TMP1, PATTERN
 | 
	
		
			
				|  |  | -+        bic     TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | -+        itt     eq
 | 
	
		
			
				|  |  | -+        andseq  TMP2, TMP2, PATTERN
 | 
	
		
			
				|  |  | -+        andseq  TMP3, TMP3, PATTERN
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/* int ff_startcode_find_candidate_armv6(const uint8_t *buf, int size) */
 | 
	
		
			
				|  |  | -+function ff_startcode_find_candidate_armv6, export=1
 | 
	
		
			
				|  |  | -+        push    {v1-v6,lr}
 | 
	
		
			
				|  |  | -+        mov     PTR, BUF
 | 
	
		
			
				|  |  | -+        @ Ensure there are at least (PRELOAD_DISTANCE+2) complete cachelines to go
 | 
	
		
			
				|  |  | -+        @ before using code that does preloads
 | 
	
		
			
				|  |  | -+        cmp     SIZE, #(PRELOAD_DISTANCE+3)*32 - 1
 | 
	
		
			
				|  |  | -+        blo     60f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        @ Get to word-alignment, 1 byte at a time
 | 
	
		
			
				|  |  | -+        tst     PTR, #3
 | 
	
		
			
				|  |  | -+        beq     2f
 | 
	
		
			
				|  |  | -+1:      ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -+        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        tst     PTR, #3
 | 
	
		
			
				|  |  | -+        bne     1b
 | 
	
		
			
				|  |  | -+2:      @ Get to 4-word alignment, 1 word at a time
 | 
	
		
			
				|  |  | -+        ldr     PATTERN, =0x80008000
 | 
	
		
			
				|  |  | -+        setend  be
 | 
	
		
			
				|  |  | -+        tst     PTR, #12
 | 
	
		
			
				|  |  | -+        beq     4f
 | 
	
		
			
				|  |  | -+3:      innerloop4
 | 
	
		
			
				|  |  | -+        bne     91f
 | 
	
		
			
				|  |  | -+        tst     PTR, #12
 | 
	
		
			
				|  |  | -+        bne     3b
 | 
	
		
			
				|  |  | -+4:      @ Get to cacheline (8-word) alignment
 | 
	
		
			
				|  |  | -+        tst     PTR, #16
 | 
	
		
			
				|  |  | -+        beq     5f
 | 
	
		
			
				|  |  | -+        innerloop16  16
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+5:      @ Check complete cachelines, with preloading
 | 
	
		
			
				|  |  | -+        @ We need to stop when there are still (PRELOAD_DISTANCE+1)
 | 
	
		
			
				|  |  | -+        @ complete cachelines to go
 | 
	
		
			
				|  |  | -+        sub     SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32
 | 
	
		
			
				|  |  | -+6:      innerloop16  , do_preload
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+        innerloop16  32
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+        bcs     6b
 | 
	
		
			
				|  |  | -+        @ Preload trailing part-cacheline, if any
 | 
	
		
			
				|  |  | -+        tst     SIZE, #31
 | 
	
		
			
				|  |  | -+        beq     7f
 | 
	
		
			
				|  |  | -+        pld     [PTR, #(PRELOAD_DISTANCE+1)*32]
 | 
	
		
			
				|  |  | -+        @ Check remaining data without doing any more preloads. First
 | 
	
		
			
				|  |  | -+        @ do in chunks of 4 words:
 | 
	
		
			
				|  |  | -+7:      adds    SIZE, SIZE, #(PRELOAD_DISTANCE+2)*32 - 16
 | 
	
		
			
				|  |  | -+        bmi     9f
 | 
	
		
			
				|  |  | -+8:      innerloop16  16
 | 
	
		
			
				|  |  | -+        bne     93f
 | 
	
		
			
				|  |  | -+        bcs     8b
 | 
	
		
			
				|  |  | -+        @ Then in words:
 | 
	
		
			
				|  |  | -+9:      adds    SIZE, SIZE, #16 - 4
 | 
	
		
			
				|  |  | -+        bmi     11f
 | 
	
		
			
				|  |  | -+10:     innerloop4
 | 
	
		
			
				|  |  | -+        bne     91f
 | 
	
		
			
				|  |  | -+        bcs     10b
 | 
	
		
			
				|  |  | -+11:     setend  le
 | 
	
		
			
				|  |  | -+        @ Check second byte of final halfword
 | 
	
		
			
				|  |  | -+        ldrb    DAT0, [PTR, #-1]
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        @ Check any remaining bytes
 | 
	
		
			
				|  |  | -+        tst     SIZE, #3
 | 
	
		
			
				|  |  | -+        beq     13f
 | 
	
		
			
				|  |  | -+12:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -+        sub     SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        tst     SIZE, #3
 | 
	
		
			
				|  |  | -+        bne     12b
 | 
	
		
			
				|  |  | -+        @ No candidate found
 | 
	
		
			
				|  |  | -+13:     sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        b       99f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+60:     @ Small buffer - simply check by looping over bytes
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        bcc     99f
 | 
	
		
			
				|  |  | -+61:     ldrb    DAT0, [PTR], #1
 | 
	
		
			
				|  |  | -+        subs    SIZE, SIZE, #1
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        beq     90f
 | 
	
		
			
				|  |  | -+        bcs     61b
 | 
	
		
			
				|  |  | -+        @ No candidate found
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        b       99f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+90:     @ Found a candidate at the preceding byte
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        sub     RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       99f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+91:     @ Found a candidate somewhere in the preceding 4 bytes
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        sub     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        itt     pl
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        bpl     92f
 | 
	
		
			
				|  |  | -+        teq     RESULT, #0
 | 
	
		
			
				|  |  | -+        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | -+        ldrb    DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | -+92:     teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+93:     @ Found a candidate somewhere in the preceding 16 bytes
 | 
	
		
			
				|  |  | -+        sub     RESULT, PTR, BUF
 | 
	
		
			
				|  |  | -+        sub     RESULT, RESULT, #16
 | 
	
		
			
				|  |  | -+        teq     TMP0, #0
 | 
	
		
			
				|  |  | -+        beq     95f @ not in first 4 bytes
 | 
	
		
			
				|  |  | -+        sub     TMP0, DAT0, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP0, TMP0, DAT0
 | 
	
		
			
				|  |  | -+        itt     pl
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-15]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        bpl     94f
 | 
	
		
			
				|  |  | -+        teq     RESULT, #0
 | 
	
		
			
				|  |  | -+        beq     98f @ don't look back a byte if found at first byte in buffer
 | 
	
		
			
				|  |  | -+        ldrb    DAT0, [PTR, #-17]
 | 
	
		
			
				|  |  | -+94:     teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+95:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        teq     TMP1, #0
 | 
	
		
			
				|  |  | -+        beq     96f @ not in next 4 bytes
 | 
	
		
			
				|  |  | -+        sub     TMP1, DAT1, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP1, TMP1, DAT1
 | 
	
		
			
				|  |  | -+        itee    mi
 | 
	
		
			
				|  |  | -+        ldrbmi  DAT0, [PTR, #-13]
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-11]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+96:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        teq     TMP2, #0
 | 
	
		
			
				|  |  | -+        beq     97f @ not in next 4 bytes
 | 
	
		
			
				|  |  | -+        sub     TMP2, DAT2, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP2, TMP2, DAT2
 | 
	
		
			
				|  |  | -+        itee    mi
 | 
	
		
			
				|  |  | -+        ldrbmi  DAT0, [PTR, #-9]
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-7]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+97:     add     RESULT, RESULT, #4
 | 
	
		
			
				|  |  | -+        sub     TMP3, DAT3, #0x20000
 | 
	
		
			
				|  |  | -+        bics    TMP3, TMP3, DAT3
 | 
	
		
			
				|  |  | -+        itee    mi
 | 
	
		
			
				|  |  | -+        ldrbmi  DAT0, [PTR, #-5]
 | 
	
		
			
				|  |  | -+        ldrbpl  DAT0, [PTR, #-3]
 | 
	
		
			
				|  |  | -+        addpl   RESULT, RESULT, #2
 | 
	
		
			
				|  |  | -+        teq     DAT0, #0
 | 
	
		
			
				|  |  | -+        it      eq
 | 
	
		
			
				|  |  | -+        subeq   RESULT, RESULT, #1
 | 
	
		
			
				|  |  | -+        @ drop through to 98f
 | 
	
		
			
				|  |  | -+98:     setend  le
 | 
	
		
			
				|  |  | -+99:     pop     {v1-v6,pc}
 | 
	
		
			
				|  |  | -+endfunc
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        .unreq  RESULT
 | 
	
		
			
				|  |  | -+        .unreq  BUF
 | 
	
		
			
				|  |  | -+        .unreq  SIZE
 | 
	
		
			
				|  |  | -+        .unreq  PATTERN
 | 
	
		
			
				|  |  | -+        .unreq  PTR
 | 
	
		
			
				|  |  | -+        .unreq  DAT0
 | 
	
		
			
				|  |  | -+        .unreq  DAT1
 | 
	
		
			
				|  |  | -+        .unreq  DAT2
 | 
	
		
			
				|  |  | -+        .unreq  DAT3
 | 
	
		
			
				|  |  | -+        .unreq  TMP0
 | 
	
		
			
				|  |  | -+        .unreq  TMP1
 | 
	
		
			
				|  |  | -+        .unreq  TMP2
 | 
	
		
			
				|  |  | -+        .unreq  TMP3
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/h264dsp.c b/lib/ffmpeg/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -index b7d61cd..a84ae59 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/h264dsp.c
 | 
	
		
			
				|  |  | -@@ -30,6 +30,7 @@
 | 
	
		
			
				|  |  | - #include "avcodec.h"
 | 
	
		
			
				|  |  | - #include "h264dsp.h"
 | 
	
		
			
				|  |  | - #include "h264idct.h"
 | 
	
		
			
				|  |  | -+#include "startcode.h"
 | 
	
		
			
				|  |  | - #include "libavutil/common.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define BIT_DEPTH 8
 | 
	
		
			
				|  |  | -@@ -60,34 +61,6 @@
 | 
	
		
			
				|  |  | - #include "h264addpx_template.c"
 | 
	
		
			
				|  |  | - #undef BIT_DEPTH
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --static int h264_find_start_code_candidate_c(const uint8_t *buf, int size)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --    int i = 0;
 | 
	
		
			
				|  |  | --#if HAVE_FAST_UNALIGNED
 | 
	
		
			
				|  |  | --    /* we check i < size instead of i + 3 / 7 because it is
 | 
	
		
			
				|  |  | --     * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
 | 
	
		
			
				|  |  | --     * bytes at the end.
 | 
	
		
			
				|  |  | --     */
 | 
	
		
			
				|  |  | --#if HAVE_FAST_64BIT
 | 
	
		
			
				|  |  | --    while (i < size &&
 | 
	
		
			
				|  |  | --            !((~*(const uint64_t *)(buf + i) &
 | 
	
		
			
				|  |  | --                    (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
 | 
	
		
			
				|  |  | --                    0x8080808080808080ULL))
 | 
	
		
			
				|  |  | --        i += 8;
 | 
	
		
			
				|  |  | --#else
 | 
	
		
			
				|  |  | --    while (i < size &&
 | 
	
		
			
				|  |  | --            !((~*(const uint32_t *)(buf + i) &
 | 
	
		
			
				|  |  | --                    (*(const uint32_t *)(buf + i) - 0x01010101U)) &
 | 
	
		
			
				|  |  | --                    0x80808080U))
 | 
	
		
			
				|  |  | --        i += 4;
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --    for (; i < size; i++)
 | 
	
		
			
				|  |  | --        if (!buf[i])
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --    return i;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_format_idc)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - #undef FUNC
 | 
	
		
			
				|  |  | -@@ -174,7 +147,7 @@ void ff_h264dsp_init(H264DSPContext *c, const int bit_depth, const int chroma_fo
 | 
	
		
			
				|  |  | -         H264_DSP(8);
 | 
	
		
			
				|  |  | -         break;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    c->h264_find_start_code_candidate = h264_find_start_code_candidate_c;
 | 
	
		
			
				|  |  | -+    c->h264_find_start_code_candidate = ff_startcode_find_candidate_c;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (ARCH_ARM) ff_h264dsp_init_arm(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | -     if (HAVE_ALTIVEC) ff_h264dsp_init_ppc(c, bit_depth, chroma_format_idc);
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/startcode.c b/lib/ffmpeg/libavcodec/startcode.c
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..5df7695
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/startcode.c
 | 
	
		
			
				|  |  | -@@ -0,0 +1,57 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ * Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * 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
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/**
 | 
	
		
			
				|  |  | -+ * @file
 | 
	
		
			
				|  |  | -+ * Accelerated start code search function for start codes common to
 | 
	
		
			
				|  |  | -+ * MPEG-1/2/4 video, VC-1, H.264/5
 | 
	
		
			
				|  |  | -+ * @author Michael Niedermayer <michaelni@gmx.at>
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "startcode.h"
 | 
	
		
			
				|  |  | -+#include "config.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int ff_startcode_find_candidate_c(const uint8_t *buf, int size)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    int i = 0;
 | 
	
		
			
				|  |  | -+#if HAVE_FAST_UNALIGNED
 | 
	
		
			
				|  |  | -+    /* we check i < size instead of i + 3 / 7 because it is
 | 
	
		
			
				|  |  | -+     * simpler and there must be FF_INPUT_BUFFER_PADDING_SIZE
 | 
	
		
			
				|  |  | -+     * bytes at the end.
 | 
	
		
			
				|  |  | -+     */
 | 
	
		
			
				|  |  | -+#       if HAVE_FAST_64BIT
 | 
	
		
			
				|  |  | -+    while (i < size &&
 | 
	
		
			
				|  |  | -+            !((~*(const uint64_t *)(buf + i) &
 | 
	
		
			
				|  |  | -+                    (*(const uint64_t *)(buf + i) - 0x0101010101010101ULL)) &
 | 
	
		
			
				|  |  | -+                    0x8080808080808080ULL))
 | 
	
		
			
				|  |  | -+        i += 8;
 | 
	
		
			
				|  |  | -+#       else
 | 
	
		
			
				|  |  | -+    while (i < size &&
 | 
	
		
			
				|  |  | -+            !((~*(const uint32_t *)(buf + i) &
 | 
	
		
			
				|  |  | -+                    (*(const uint32_t *)(buf + i) - 0x01010101U)) &
 | 
	
		
			
				|  |  | -+                    0x80808080U))
 | 
	
		
			
				|  |  | -+        i += 4;
 | 
	
		
			
				|  |  | -+#       endif
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+    for (; i < size; i++)
 | 
	
		
			
				|  |  | -+        if (!buf[i])
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+    return i;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/startcode.h b/lib/ffmpeg/libavcodec/startcode.h
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..cc55d5f
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/startcode.h
 | 
	
		
			
				|  |  | -@@ -0,0 +1,35 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ * Copyright (c) 2003-2010 Michael Niedermayer <michaelni@gmx.at>
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * 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
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/**
 | 
	
		
			
				|  |  | -+ * @file
 | 
	
		
			
				|  |  | -+ * Accelerated start code search function for start codes common to
 | 
	
		
			
				|  |  | -+ * MPEG-1/2/4 video, VC-1, H.264/5
 | 
	
		
			
				|  |  | -+ * @author Michael Niedermayer <michaelni@gmx.at>
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#ifndef AVCODEC_STARTCODE_H
 | 
	
		
			
				|  |  | -+#define AVCODEC_STARTCODE_H
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include <stdint.h>
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int ff_startcode_find_candidate_c(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#endif /* AVCODEC_STARTCODE_H */
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7d95eb8e026582e5446e7e11d75ba999286a34d0 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 16 Apr 2014 01:51:32 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 06/94] vc-1: Add platform-specific start code search routine
 | 
	
		
			
				|  |  | - to VC1DSPContext.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Initialise VC1DSPContext for parser as well as for decoder.
 | 
	
		
			
				|  |  | -Note, the VC-1 code doesn't actually use the function pointer yet.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/Makefile              |  7 +++---
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/Makefile          |  3 +++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c | 33 +++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/vc1.c                 |  2 ++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/vc1dec.c              |  1 -
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/vc1dsp.c              |  5 +++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/vc1dsp.h              |  9 ++++++++
 | 
	
		
			
				|  |  | - 7 files changed, 56 insertions(+), 4 deletions(-)
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/Makefile b/lib/ffmpeg/libavcodec/Makefile
 | 
	
		
			
				|  |  | -index 460f42c..8d8a548 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/Makefile
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/Makefile
 | 
	
		
			
				|  |  | -@@ -455,7 +455,7 @@ OBJS-$(CONFIG_VB_DECODER)              += vb.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VBLE_DECODER)            += vble.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VC1_DECODER)             += vc1dec.o vc1.o vc1data.o vc1dsp.o \
 | 
	
		
			
				|  |  | -                                           msmpeg4.o msmpeg4data.o           \
 | 
	
		
			
				|  |  | --                                          intrax8.o intrax8dsp.o
 | 
	
		
			
				|  |  | -+                                          intrax8.o intrax8dsp.o startcode.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VC1_DXVA2_HWACCEL)       += dxva2_vc1.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VC1_VAAPI_HWACCEL)       += vaapi_vc1.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VC1_VDPAU_HWACCEL)       += vdpau_vc1.o
 | 
	
		
			
				|  |  | -@@ -487,6 +487,7 @@ OBJS-$(CONFIG_WMAVOICE_DECODER)        += wmavoice.o \
 | 
	
		
			
				|  |  | -                                           celp_filters.o \
 | 
	
		
			
				|  |  | -                                           acelp_vectors.o acelp_filters.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_WMV1_DECODER)            += msmpeg4.o msmpeg4data.o
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_WMV2_DECODER)            += wmv2dec.o wmv2.o wmv2dsp.o \
 | 
	
		
			
				|  |  | -                                           msmpeg4.o msmpeg4data.o \
 | 
	
		
			
				|  |  | -                                           intrax8.o intrax8dsp.o
 | 
	
		
			
				|  |  | -@@ -746,9 +747,9 @@ OBJS-$(CONFIG_PNM_PARSER)              += pnm_parser.o pnm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_RV30_PARSER)             += rv34_parser.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_RV40_PARSER)             += rv34_parser.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_TAK_PARSER)              += tak_parser.o tak.o
 | 
	
		
			
				|  |  | --OBJS-$(CONFIG_VC1_PARSER)              += vc1_parser.o vc1.o vc1data.o \
 | 
	
		
			
				|  |  | -+OBJS-$(CONFIG_VC1_PARSER)              += vc1_parser.o vc1.o vc1data.o vc1dsp.o \
 | 
	
		
			
				|  |  | -                                           msmpeg4.o msmpeg4data.o mpeg4video.o \
 | 
	
		
			
				|  |  | --                                          h263.o
 | 
	
		
			
				|  |  | -+                                          h263.o startcode.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VORBIS_PARSER)           += vorbis_parser.o xiph.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VP3_PARSER)              += vp3_parser.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VP8_PARSER)              += vp8_parser.o
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -index 0b432e3..715eed7 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -@@ -16,6 +16,9 @@ OBJS-$(CONFIG_FLAC_DECODER)            += arm/flacdsp_init_arm.o        \
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_MPEGAUDIODSP)            += arm/mpegaudiodsp_init_arm.o
 | 
	
		
			
				|  |  | - ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP)      += arm/mpegaudiodsp_fixed_armv6.o
 | 
	
		
			
				|  |  | -+ARMV6-OBJS-$(CONFIG_VC1_DECODER)       += arm/startcode_armv6.o
 | 
	
		
			
				|  |  | -+OBJS-$(CONFIG_VC1_DECODER)             += arm/vc1dsp_init_arm.o
 | 
	
		
			
				|  |  | -+ARMV6-OBJS-$(CONFIG_VC1_PARSER)        += arm/startcode_armv6.o
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_MPEGVIDEO)               += arm/mpegvideo_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VORBIS_DECODER)          += arm/vorbisdsp_init_arm.o
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..fec5e78
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/vc1dsp_init_arm.c
 | 
	
		
			
				|  |  | -@@ -0,0 +1,33 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ * This file is part of Libav.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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 Libav; if not, write to the Free Software
 | 
	
		
			
				|  |  | -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include <stdint.h>
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "libavutil/attributes.h"
 | 
	
		
			
				|  |  | -+#include "libavutil/arm/cpu.h"
 | 
	
		
			
				|  |  | -+#include "libavcodec/vc1dsp.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int ff_startcode_find_candidate_armv6(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+av_cold void ff_vc1dsp_init_arm(VC1DSPContext *dsp)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    int cpu_flags = av_get_cpu_flags();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (have_armv6(cpu_flags))
 | 
	
		
			
				|  |  | -+        dsp->vc1_find_start_code_candidate = ff_startcode_find_candidate_armv6;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/vc1.c b/lib/ffmpeg/libavcodec/vc1.c
 | 
	
		
			
				|  |  | -index e2e90a8..9b15809 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/vc1.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/vc1.c
 | 
	
		
			
				|  |  | -@@ -1663,5 +1663,7 @@ int ff_vc1_init_common(VC1Context *v)
 | 
	
		
			
				|  |  | -     v->pq      = -1;
 | 
	
		
			
				|  |  | -     v->mvrange = 0; /* 7.1.1.18, p80 */
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    ff_vc1dsp_init(&v->vc1dsp);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     return 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/vc1dec.c b/lib/ffmpeg/libavcodec/vc1dec.c
 | 
	
		
			
				|  |  | -index 2130c74..9fd3cae 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/vc1dec.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/vc1dec.c
 | 
	
		
			
				|  |  | -@@ -5193,7 +5193,6 @@ static av_cold int vc1_decode_init(AVCodecContext *avctx)
 | 
	
		
			
				|  |  | -     ff_vc1_decode_end(avctx);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     ff_h264chroma_init(&v->h264chroma, 8);
 | 
	
		
			
				|  |  | --    ff_vc1dsp_init(&v->vc1dsp);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (avctx->codec_id == AV_CODEC_ID_WMV3 || avctx->codec_id == AV_CODEC_ID_WMV3IMAGE) {
 | 
	
		
			
				|  |  | -         int count = 0;
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/vc1dsp.c b/lib/ffmpeg/libavcodec/vc1dsp.c
 | 
	
		
			
				|  |  | -index 260eda4..3e3f00e 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/vc1dsp.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/vc1dsp.c
 | 
	
		
			
				|  |  | -@@ -30,6 +30,7 @@
 | 
	
		
			
				|  |  | - #include "h264chroma.h"
 | 
	
		
			
				|  |  | - #include "rnd_avg.h"
 | 
	
		
			
				|  |  | - #include "vc1dsp.h"
 | 
	
		
			
				|  |  | -+#include "startcode.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - /** Apply overlap transform to horizontal edge
 | 
	
		
			
				|  |  | -@@ -861,8 +862,12 @@ av_cold void ff_vc1dsp_init(VC1DSPContext* dsp) {
 | 
	
		
			
				|  |  | -     dsp->sprite_v_double_twoscale = sprite_v_double_twoscale_c;
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    dsp->vc1_find_start_code_candidate = ff_startcode_find_candidate_c;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     if (HAVE_ALTIVEC)
 | 
	
		
			
				|  |  | -         ff_vc1dsp_init_altivec(dsp);
 | 
	
		
			
				|  |  | -+    if (ARCH_ARM)
 | 
	
		
			
				|  |  | -+        ff_vc1dsp_init_arm(dsp);
 | 
	
		
			
				|  |  | -     if (ARCH_X86)
 | 
	
		
			
				|  |  | -         ff_vc1dsp_init_x86(dsp);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/vc1dsp.h b/lib/ffmpeg/libavcodec/vc1dsp.h
 | 
	
		
			
				|  |  | -index 6540eff..302e4a8 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/vc1dsp.h
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/vc1dsp.h
 | 
	
		
			
				|  |  | -@@ -73,10 +73,19 @@ typedef struct VC1DSPContext {
 | 
	
		
			
				|  |  | -     void (*sprite_v_double_twoscale)(uint8_t *dst, const uint8_t *src1a, const uint8_t *src1b, int offset1,
 | 
	
		
			
				|  |  | -                                                    const uint8_t *src2a, const uint8_t *src2b, int offset2,
 | 
	
		
			
				|  |  | -                                      int alpha, int width);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    /**
 | 
	
		
			
				|  |  | -+     * Search buf from the start for up to size bytes. Return the index
 | 
	
		
			
				|  |  | -+     * of a zero byte, or >= size if not found. Ideally, use lookahead
 | 
	
		
			
				|  |  | -+     * to filter out any zero bytes that are known to not be followed by
 | 
	
		
			
				|  |  | -+     * one or more further zero bytes and a one byte.
 | 
	
		
			
				|  |  | -+     */
 | 
	
		
			
				|  |  | -+    int (*vc1_find_start_code_candidate)(const uint8_t *buf, int size);
 | 
	
		
			
				|  |  | - } VC1DSPContext;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void ff_vc1dsp_init(VC1DSPContext* c);
 | 
	
		
			
				|  |  | - void ff_vc1dsp_init_altivec(VC1DSPContext* c);
 | 
	
		
			
				|  |  | -+void ff_vc1dsp_init_arm(VC1DSPContext* dsp);
 | 
	
		
			
				|  |  | - void ff_vc1dsp_init_x86(VC1DSPContext* dsp);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif /* AVCODEC_VC1DSP_H */
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 9b459c3c4130299099b2e5aca5bff3d6f8d60e72 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 23 Apr 2014 01:41:04 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 07/94] vc-1: Optimise parser (with special attention to ARM)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The previous implementation of the parser made four passes over each input
 | 
	
		
			
				|  |  | -buffer (reduced to two if the container format already guaranteed the input
 | 
	
		
			
				|  |  | -buffer corresponded to frames, such as with MKV). But these buffers are
 | 
	
		
			
				|  |  | -often 200K in size, certainly enough to flush the data out of L1 cache, and
 | 
	
		
			
				|  |  | -for many CPUs, all the way out to main memory. The passes were:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -1) locate frame boundaries (not needed for MKV etc)
 | 
	
		
			
				|  |  | -2) copy the data into a contiguous block (not needed for MKV etc)
 | 
	
		
			
				|  |  | -3) locate the start codes within each frame
 | 
	
		
			
				|  |  | -4) unescape the data between start codes
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -After this, the unescaped data was parsed to extract certain header fields,
 | 
	
		
			
				|  |  | -but because the unescape operation was so large, this was usually also
 | 
	
		
			
				|  |  | -effectively operating on uncached memory. Most of the unescaped data was
 | 
	
		
			
				|  |  | -simply thrown away and never processed further. Only step 2 - because it
 | 
	
		
			
				|  |  | -used memcpy - was using prefetch, making things even worse.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This patch reorganises these steps so that, aside from the copying, the
 | 
	
		
			
				|  |  | -operations are performed in parallel, maximising cache utilisation. No more
 | 
	
		
			
				|  |  | -than the worst-case number of bytes needed for header parsing is unescaped.
 | 
	
		
			
				|  |  | -Most of the data is, in practice, only read in order to search for a start
 | 
	
		
			
				|  |  | -code, for which optimised implementations already existed in the H264 codec
 | 
	
		
			
				|  |  | -(notably the ARM version uses prefetch, so we end up doing both remaining
 | 
	
		
			
				|  |  | -passes at maximum speed). For MKV files, we know when we've found the last
 | 
	
		
			
				|  |  | -start code of interest in a given frame, so we are able to avoid doing even
 | 
	
		
			
				|  |  | -that one remaining pass for most of the buffer.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -In some use-cases (such as the Raspberry Pi) video decode is handled by the
 | 
	
		
			
				|  |  | -GPU, but the entire elementary stream is still fed through the parser to
 | 
	
		
			
				|  |  | -pick out certain elements of the header which are necessary to manage the
 | 
	
		
			
				|  |  | -decode process. As you might expect, in these cases, the performance of the
 | 
	
		
			
				|  |  | -parser is significant.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -To measure parser performance, I used the same VC-1 elementary stream in
 | 
	
		
			
				|  |  | -either an MPEG-2 transport stream or a MKV file, and fed it through ffmpeg
 | 
	
		
			
				|  |  | -with -c:v copy -c:a copy -f null. These are the gperftools counts for
 | 
	
		
			
				|  |  | -those streams, both filtered to only include vc1_parse() and its callees,
 | 
	
		
			
				|  |  | -and unfiltered (to include the whole binary). Lower numbers are better:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                Before          After
 | 
	
		
			
				|  |  | -File  Filtered  Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -M2TS  No        861.7  8.2      650.5  8.1     100.0%      +32.5%
 | 
	
		
			
				|  |  | -MKV   No        868.9  7.4      731.7  9.0     100.0%      +18.8%
 | 
	
		
			
				|  |  | -M2TS  Yes       250.0  11.2     27.2   3.4     100.0%      +817.9%
 | 
	
		
			
				|  |  | -MKV   Yes       149.0  12.8     1.7    0.8     100.0%      +8526.3%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Yes, that last case shows vc1_parse() running 86 times faster! The M2TS
 | 
	
		
			
				|  |  | -case does show a larger absolute improvement though, since it was worse
 | 
	
		
			
				|  |  | -to begin with.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This patch has been tested with the FATE suite (albeit on x86 for speed).
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/vc1_parser.c | 269 ++++++++++++++++++++++++-------------
 | 
	
		
			
				|  |  | - 1 file changed, 175 insertions(+), 94 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/vc1_parser.c b/lib/ffmpeg/libavcodec/vc1_parser.c
 | 
	
		
			
				|  |  | -index 53af61c..af601ad 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/vc1_parser.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/vc1_parser.c
 | 
	
		
			
				|  |  | -@@ -29,112 +29,83 @@
 | 
	
		
			
				|  |  | - #include "vc1.h"
 | 
	
		
			
				|  |  | - #include "get_bits.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+/** The maximum number of bytes of a sequence, entry point or
 | 
	
		
			
				|  |  | -+ *  frame header whose values we pay any attention to */
 | 
	
		
			
				|  |  | -+#define UNESCAPED_THRESHOLD 37
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/** The maximum number of bytes of a sequence, entry point or
 | 
	
		
			
				|  |  | -+ *  frame header which must be valid memory (because they are
 | 
	
		
			
				|  |  | -+ *  used to update the bitstream cache in skip_bits() calls)
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+#define UNESCAPED_LIMIT 144
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+typedef enum {
 | 
	
		
			
				|  |  | -+    NO_MATCH,
 | 
	
		
			
				|  |  | -+    ONE_ZERO,
 | 
	
		
			
				|  |  | -+    TWO_ZEROS,
 | 
	
		
			
				|  |  | -+    ONE
 | 
	
		
			
				|  |  | -+} VC1ParseSearchState;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - typedef struct {
 | 
	
		
			
				|  |  | -     ParseContext pc;
 | 
	
		
			
				|  |  | -     VC1Context v;
 | 
	
		
			
				|  |  | -+    uint8_t prev_start_code;
 | 
	
		
			
				|  |  | -+    size_t bytes_to_skip;
 | 
	
		
			
				|  |  | -+    uint8_t unesc_buffer[UNESCAPED_LIMIT];
 | 
	
		
			
				|  |  | -+    size_t unesc_index;
 | 
	
		
			
				|  |  | -+    VC1ParseSearchState search_state;
 | 
	
		
			
				|  |  | - } VC1ParseContext;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --static void vc1_extract_headers(AVCodecParserContext *s, AVCodecContext *avctx,
 | 
	
		
			
				|  |  | --                                const uint8_t *buf, int buf_size)
 | 
	
		
			
				|  |  | -+static void vc1_extract_header(AVCodecParserContext *s, AVCodecContext *avctx,
 | 
	
		
			
				|  |  | -+                               const uint8_t *buf, int buf_size)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+    /* Parse the header we just finished unescaping */
 | 
	
		
			
				|  |  | -     VC1ParseContext *vpc = s->priv_data;
 | 
	
		
			
				|  |  | -     GetBitContext gb;
 | 
	
		
			
				|  |  | --    const uint8_t *start, *end, *next;
 | 
	
		
			
				|  |  | --    uint8_t *buf2 = av_mallocz(buf_size + FF_INPUT_BUFFER_PADDING_SIZE);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+    int ret;
 | 
	
		
			
				|  |  | -     vpc->v.s.avctx = avctx;
 | 
	
		
			
				|  |  | -     vpc->v.parse_only = 1;
 | 
	
		
			
				|  |  | --    next = buf;
 | 
	
		
			
				|  |  | --    s->repeat_pict = 0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    for(start = buf, end = buf + buf_size; next < end; start = next){
 | 
	
		
			
				|  |  | --        int buf2_size, size;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --        next = find_next_marker(start + 4, end);
 | 
	
		
			
				|  |  | --        size = next - start - 4;
 | 
	
		
			
				|  |  | --        buf2_size = vc1_unescape_buffer(start + 4, size, buf2);
 | 
	
		
			
				|  |  | --        init_get_bits(&gb, buf2, buf2_size * 8);
 | 
	
		
			
				|  |  | --        if(size <= 0) continue;
 | 
	
		
			
				|  |  | --        switch(AV_RB32(start)){
 | 
	
		
			
				|  |  | --        case VC1_CODE_SEQHDR:
 | 
	
		
			
				|  |  | --            ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --        case VC1_CODE_ENTRYPOINT:
 | 
	
		
			
				|  |  | --            ff_vc1_decode_entry_point(avctx, &vpc->v, &gb);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --        case VC1_CODE_FRAME:
 | 
	
		
			
				|  |  | --            if(vpc->v.profile < PROFILE_ADVANCED)
 | 
	
		
			
				|  |  | --                ff_vc1_parse_frame_header    (&vpc->v, &gb);
 | 
	
		
			
				|  |  | --            else
 | 
	
		
			
				|  |  | --                ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --            /* keep AV_PICTURE_TYPE_BI internal to VC1 */
 | 
	
		
			
				|  |  | --            if (vpc->v.s.pict_type == AV_PICTURE_TYPE_BI)
 | 
	
		
			
				|  |  | --                s->pict_type = AV_PICTURE_TYPE_B;
 | 
	
		
			
				|  |  | --            else
 | 
	
		
			
				|  |  | --                s->pict_type = vpc->v.s.pict_type;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --            if (avctx->ticks_per_frame > 1){
 | 
	
		
			
				|  |  | --                // process pulldown flags
 | 
	
		
			
				|  |  | --                s->repeat_pict = 1;
 | 
	
		
			
				|  |  | --                // Pulldown flags are only valid when 'broadcast' has been set.
 | 
	
		
			
				|  |  | --                // So ticks_per_frame will be 2
 | 
	
		
			
				|  |  | --                if (vpc->v.rff){
 | 
	
		
			
				|  |  | --                    // repeat field
 | 
	
		
			
				|  |  | --                    s->repeat_pict = 2;
 | 
	
		
			
				|  |  | --                }else if (vpc->v.rptfrm){
 | 
	
		
			
				|  |  | --                    // repeat frames
 | 
	
		
			
				|  |  | --                    s->repeat_pict = vpc->v.rptfrm * 2 + 1;
 | 
	
		
			
				|  |  | --                }
 | 
	
		
			
				|  |  | --            }
 | 
	
		
			
				|  |  | -+    init_get_bits(&gb, buf, buf_size * 8);
 | 
	
		
			
				|  |  | -+    switch (vpc->prev_start_code) {
 | 
	
		
			
				|  |  | -+    case VC1_CODE_SEQHDR & 0xFF:
 | 
	
		
			
				|  |  | -+        ff_vc1_decode_sequence_header(avctx, &vpc->v, &gb);
 | 
	
		
			
				|  |  | -+        break;
 | 
	
		
			
				|  |  | -+    case VC1_CODE_ENTRYPOINT & 0xFF:
 | 
	
		
			
				|  |  | -+        ff_vc1_decode_entry_point(avctx, &vpc->v, &gb);
 | 
	
		
			
				|  |  | -+        break;
 | 
	
		
			
				|  |  | -+    case VC1_CODE_FRAME & 0xFF:
 | 
	
		
			
				|  |  | -+        if(vpc->v.profile < PROFILE_ADVANCED)
 | 
	
		
			
				|  |  | -+            ret = ff_vc1_parse_frame_header    (&vpc->v, &gb);
 | 
	
		
			
				|  |  | -+        else
 | 
	
		
			
				|  |  | -+            ret = ff_vc1_parse_frame_header_adv(&vpc->v, &gb);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+        if (ret < 0)
 | 
	
		
			
				|  |  | -             break;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    av_free(buf2);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | -+        /* keep AV_PICTURE_TYPE_BI internal to VC1 */
 | 
	
		
			
				|  |  | -+        if (vpc->v.s.pict_type == AV_PICTURE_TYPE_BI)
 | 
	
		
			
				|  |  | -+            s->pict_type = AV_PICTURE_TYPE_B;
 | 
	
		
			
				|  |  | -+        else
 | 
	
		
			
				|  |  | -+            s->pict_type = vpc->v.s.pict_type;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --/**
 | 
	
		
			
				|  |  | -- * Find the end of the current frame in the bitstream.
 | 
	
		
			
				|  |  | -- * @return the position of the first byte of the next frame, or -1
 | 
	
		
			
				|  |  | -- */
 | 
	
		
			
				|  |  | --static int vc1_find_frame_end(ParseContext *pc, const uint8_t *buf,
 | 
	
		
			
				|  |  | --                               int buf_size) {
 | 
	
		
			
				|  |  | --    int pic_found, i;
 | 
	
		
			
				|  |  | --    uint32_t state;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    pic_found= pc->frame_start_found;
 | 
	
		
			
				|  |  | --    state= pc->state;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    i=0;
 | 
	
		
			
				|  |  | --    if(!pic_found){
 | 
	
		
			
				|  |  | --        for(i=0; i<buf_size; i++){
 | 
	
		
			
				|  |  | --            state= (state<<8) | buf[i];
 | 
	
		
			
				|  |  | --            if(state == VC1_CODE_FRAME || state == VC1_CODE_FIELD){
 | 
	
		
			
				|  |  | --                i++;
 | 
	
		
			
				|  |  | --                pic_found=1;
 | 
	
		
			
				|  |  | --                break;
 | 
	
		
			
				|  |  | -+        if (avctx->ticks_per_frame > 1){
 | 
	
		
			
				|  |  | -+            // process pulldown flags
 | 
	
		
			
				|  |  | -+            s->repeat_pict = 1;
 | 
	
		
			
				|  |  | -+            // Pulldown flags are only valid when 'broadcast' has been set.
 | 
	
		
			
				|  |  | -+            // So ticks_per_frame will be 2
 | 
	
		
			
				|  |  | -+            if (vpc->v.rff){
 | 
	
		
			
				|  |  | -+                // repeat field
 | 
	
		
			
				|  |  | -+                s->repeat_pict = 2;
 | 
	
		
			
				|  |  | -+            }else if (vpc->v.rptfrm){
 | 
	
		
			
				|  |  | -+                // repeat frames
 | 
	
		
			
				|  |  | -+                s->repeat_pict = vpc->v.rptfrm * 2 + 1;
 | 
	
		
			
				|  |  | -             }
 | 
	
		
			
				|  |  | -+        }else{
 | 
	
		
			
				|  |  | -+            s->repeat_pict = 0;
 | 
	
		
			
				|  |  | -         }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    if(pic_found){
 | 
	
		
			
				|  |  | --        /* EOF considered as end of frame */
 | 
	
		
			
				|  |  | --        if (buf_size == 0)
 | 
	
		
			
				|  |  | --            return 0;
 | 
	
		
			
				|  |  | --        for(; i<buf_size; i++){
 | 
	
		
			
				|  |  | --            state= (state<<8) | buf[i];
 | 
	
		
			
				|  |  | --            if(IS_MARKER(state) && state != VC1_CODE_FIELD && state != VC1_CODE_SLICE){
 | 
	
		
			
				|  |  | --                pc->frame_start_found=0;
 | 
	
		
			
				|  |  | --                pc->state=-1;
 | 
	
		
			
				|  |  | --                return i-3;
 | 
	
		
			
				|  |  | --            }
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | -+        break;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    pc->frame_start_found= pic_found;
 | 
	
		
			
				|  |  | --    pc->state= state;
 | 
	
		
			
				|  |  | --    return END_NOT_FOUND;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - static int vc1_parse(AVCodecParserContext *s,
 | 
	
		
			
				|  |  | -@@ -142,22 +113,127 @@ static int vc1_parse(AVCodecParserContext *s,
 | 
	
		
			
				|  |  | -                            const uint8_t **poutbuf, int *poutbuf_size,
 | 
	
		
			
				|  |  | -                            const uint8_t *buf, int buf_size)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+    /* Here we do the searching for frame boundaries and headers at
 | 
	
		
			
				|  |  | -+     * the same time. Only a minimal amount at the start of each
 | 
	
		
			
				|  |  | -+     * header is unescaped. */
 | 
	
		
			
				|  |  | -     VC1ParseContext *vpc = s->priv_data;
 | 
	
		
			
				|  |  | --    int next;
 | 
	
		
			
				|  |  | -+    int pic_found = vpc->pc.frame_start_found;
 | 
	
		
			
				|  |  | -+    uint8_t *unesc_buffer = vpc->unesc_buffer;
 | 
	
		
			
				|  |  | -+    size_t unesc_index = vpc->unesc_index;
 | 
	
		
			
				|  |  | -+    VC1ParseSearchState search_state = vpc->search_state;
 | 
	
		
			
				|  |  | -+    int next = END_NOT_FOUND;
 | 
	
		
			
				|  |  | -+    int i = vpc->bytes_to_skip;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    if(s->flags & PARSER_FLAG_COMPLETE_FRAMES){
 | 
	
		
			
				|  |  | --        next= buf_size;
 | 
	
		
			
				|  |  | --    }else{
 | 
	
		
			
				|  |  | --        next= vc1_find_frame_end(&vpc->pc, buf, buf_size);
 | 
	
		
			
				|  |  | -+    if (pic_found && buf_size == 0) {
 | 
	
		
			
				|  |  | -+        /* EOF considered as end of frame */
 | 
	
		
			
				|  |  | -+        memset(unesc_buffer + unesc_index, 0, UNESCAPED_THRESHOLD - unesc_index);
 | 
	
		
			
				|  |  | -+        vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
 | 
	
		
			
				|  |  | -+        next = 0;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    while (i < buf_size) {
 | 
	
		
			
				|  |  | -+        int start_code_found = 0;
 | 
	
		
			
				|  |  | -+        uint8_t b;
 | 
	
		
			
				|  |  | -+        while (i < buf_size && unesc_index < UNESCAPED_THRESHOLD) {
 | 
	
		
			
				|  |  | -+            b = buf[i++];
 | 
	
		
			
				|  |  | -+            unesc_buffer[unesc_index++] = b;
 | 
	
		
			
				|  |  | -+            if (search_state <= ONE_ZERO)
 | 
	
		
			
				|  |  | -+                search_state = b ? NO_MATCH : search_state + 1;
 | 
	
		
			
				|  |  | -+            else if (search_state == TWO_ZEROS) {
 | 
	
		
			
				|  |  | -+                if (b == 1)
 | 
	
		
			
				|  |  | -+                    search_state = ONE;
 | 
	
		
			
				|  |  | -+                else if (b > 1) {
 | 
	
		
			
				|  |  | -+                    if (b == 3)
 | 
	
		
			
				|  |  | -+                        unesc_index--; // swallow emulation prevention byte
 | 
	
		
			
				|  |  | -+                    search_state = NO_MATCH;
 | 
	
		
			
				|  |  | -+                }
 | 
	
		
			
				|  |  | -+            }
 | 
	
		
			
				|  |  | -+            else { // search_state == ONE
 | 
	
		
			
				|  |  | -+                // Header unescaping terminates early due to detection of next start code
 | 
	
		
			
				|  |  | -+                search_state = NO_MATCH;
 | 
	
		
			
				|  |  | -+                start_code_found = 1;
 | 
	
		
			
				|  |  | -+                break;
 | 
	
		
			
				|  |  | -+            }
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+        if ((s->flags & PARSER_FLAG_COMPLETE_FRAMES) &&
 | 
	
		
			
				|  |  | -+                unesc_index >= UNESCAPED_THRESHOLD &&
 | 
	
		
			
				|  |  | -+                vpc->prev_start_code == (VC1_CODE_FRAME & 0xFF))
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+            // No need to keep scanning the rest of the buffer for
 | 
	
		
			
				|  |  | -+            // start codes if we know it contains a complete frame and
 | 
	
		
			
				|  |  | -+            // we've already unescaped all we need of the frame header
 | 
	
		
			
				|  |  | -+            vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+        if (unesc_index >= UNESCAPED_THRESHOLD && !start_code_found) {
 | 
	
		
			
				|  |  | -+            while (i < buf_size) {
 | 
	
		
			
				|  |  | -+                if (search_state == NO_MATCH) {
 | 
	
		
			
				|  |  | -+                    i += vpc->v.vc1dsp.vc1_find_start_code_candidate(buf + i, buf_size - i);
 | 
	
		
			
				|  |  | -+                    if (i < buf_size) {
 | 
	
		
			
				|  |  | -+                        search_state = ONE_ZERO;
 | 
	
		
			
				|  |  | -+                    }
 | 
	
		
			
				|  |  | -+                    i++;
 | 
	
		
			
				|  |  | -+                } else {
 | 
	
		
			
				|  |  | -+                    b = buf[i++];
 | 
	
		
			
				|  |  | -+                    if (search_state == ONE_ZERO)
 | 
	
		
			
				|  |  | -+                        search_state = b ? NO_MATCH : TWO_ZEROS;
 | 
	
		
			
				|  |  | -+                    else if (search_state == TWO_ZEROS) {
 | 
	
		
			
				|  |  | -+                        if (b >= 1)
 | 
	
		
			
				|  |  | -+                            search_state = b == 1 ? ONE : NO_MATCH;
 | 
	
		
			
				|  |  | -+                    }
 | 
	
		
			
				|  |  | -+                    else { // search_state == ONE
 | 
	
		
			
				|  |  | -+                        search_state = NO_MATCH;
 | 
	
		
			
				|  |  | -+                        start_code_found = 1;
 | 
	
		
			
				|  |  | -+                        break;
 | 
	
		
			
				|  |  | -+                    }
 | 
	
		
			
				|  |  | -+                }
 | 
	
		
			
				|  |  | -+            }
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+        if (start_code_found) {
 | 
	
		
			
				|  |  | -+            vc1_extract_header(s, avctx, unesc_buffer, unesc_index);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+            vpc->prev_start_code = b;
 | 
	
		
			
				|  |  | -+            unesc_index = 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+            if (!(s->flags & PARSER_FLAG_COMPLETE_FRAMES)) {
 | 
	
		
			
				|  |  | -+                if (!pic_found && (b == (VC1_CODE_FRAME & 0xFF) || b == (VC1_CODE_FIELD & 0xFF))) {
 | 
	
		
			
				|  |  | -+                    pic_found = 1;
 | 
	
		
			
				|  |  | -+                }
 | 
	
		
			
				|  |  | -+                else if (pic_found && b != (VC1_CODE_FIELD & 0xFF) && b != (VC1_CODE_SLICE & 0xFF)) {
 | 
	
		
			
				|  |  | -+                    next = i - 4;
 | 
	
		
			
				|  |  | -+                    pic_found = b == (VC1_CODE_FRAME & 0xFF);
 | 
	
		
			
				|  |  | -+                    break;
 | 
	
		
			
				|  |  | -+                }
 | 
	
		
			
				|  |  | -+            }
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    vpc->pc.frame_start_found = pic_found;
 | 
	
		
			
				|  |  | -+    vpc->unesc_index = unesc_index;
 | 
	
		
			
				|  |  | -+    vpc->search_state = search_state;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (s->flags & PARSER_FLAG_COMPLETE_FRAMES) {
 | 
	
		
			
				|  |  | -+        next = buf_size;
 | 
	
		
			
				|  |  | -+    } else {
 | 
	
		
			
				|  |  | -         if (ff_combine_frame(&vpc->pc, next, &buf, &buf_size) < 0) {
 | 
	
		
			
				|  |  | -+            vpc->bytes_to_skip = 0;
 | 
	
		
			
				|  |  | -             *poutbuf = NULL;
 | 
	
		
			
				|  |  | -             *poutbuf_size = 0;
 | 
	
		
			
				|  |  | -             return buf_size;
 | 
	
		
			
				|  |  | -         }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    vc1_extract_headers(s, avctx, buf, buf_size);
 | 
	
		
			
				|  |  | -+    vpc->v.first_pic_header_flag = 1;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    /* If we return with a valid pointer to a combined frame buffer
 | 
	
		
			
				|  |  | -+     * then on the next call then we'll have been unhelpfully rewound
 | 
	
		
			
				|  |  | -+     * by up to 4 bytes (depending upon whether the start code
 | 
	
		
			
				|  |  | -+     * overlapped the input buffer, and if so by how much). We don't
 | 
	
		
			
				|  |  | -+     * want this: it will either cause spurious second detections of
 | 
	
		
			
				|  |  | -+     * the start code we've already seen, or cause extra bytes to be
 | 
	
		
			
				|  |  | -+     * inserted at the start of the unescaped buffer. */
 | 
	
		
			
				|  |  | -+    vpc->bytes_to_skip = 4;
 | 
	
		
			
				|  |  | -+    if (next < 0)
 | 
	
		
			
				|  |  | -+        vpc->bytes_to_skip += next;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     *poutbuf = buf;
 | 
	
		
			
				|  |  | -     *poutbuf_size = buf_size;
 | 
	
		
			
				|  |  | -@@ -188,6 +264,11 @@ static int vc1_parse_init(AVCodecParserContext *s)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -     VC1ParseContext *vpc = s->priv_data;
 | 
	
		
			
				|  |  | -     vpc->v.s.slice_context_count = 1;
 | 
	
		
			
				|  |  | -+    vpc->v.first_pic_header_flag = 1;
 | 
	
		
			
				|  |  | -+    vpc->prev_start_code = 0;
 | 
	
		
			
				|  |  | -+    vpc->bytes_to_skip = 0;
 | 
	
		
			
				|  |  | -+    vpc->unesc_index = 0;
 | 
	
		
			
				|  |  | -+    vpc->search_state = NO_MATCH;
 | 
	
		
			
				|  |  | -     return ff_vc1_init_common(&vpc->v);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From c2ebe54fe1d7c7a6cee7282bcf2668a826006ade Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 19 Mar 2014 17:44:59 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 08/94]  truehd: add hand-scheduled ARM asm version of
 | 
	
		
			
				|  |  | - mlp_filter_channel.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Profiling results for overall audio decode and the mlp_filter_channel(_arm)
 | 
	
		
			
				|  |  | -function in particular are as follows:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -              Before          After
 | 
	
		
			
				|  |  | -              Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -6:2 total     380.4  22.0     370.8  17.0    87.4%       +2.6%  (insignificant)
 | 
	
		
			
				|  |  | -6:2 function  60.7   7.2      36.6   8.1     100.0%      +65.8%
 | 
	
		
			
				|  |  | -8:2 total     357.0  17.5     343.2  19.0    97.8%       +4.0%  (insignificant)
 | 
	
		
			
				|  |  | -8:2 function  60.3   8.8      37.3   3.8     100.0%      +61.8%
 | 
	
		
			
				|  |  | -6:6 total     717.2  23.2     658.4  15.7    100.0%      +8.9%
 | 
	
		
			
				|  |  | -6:6 function  140.4  12.9     81.5   9.2     100.0%      +72.4%
 | 
	
		
			
				|  |  | -8:8 total     981.9  16.2     896.2  24.5    100.0%      +9.6%
 | 
	
		
			
				|  |  | -8:8 function  193.4  15.0     103.3  11.5    100.0%      +87.2%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Experiments with adding preload instructions to this function yielded no
 | 
	
		
			
				|  |  | -useful benefit, so these have not been included.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The assembly version has also been tested with a fuzz tester to ensure that
 | 
	
		
			
				|  |  | -any combinations of inputs not exercised by my available test streams still
 | 
	
		
			
				|  |  | -generate mathematically identical results to the C version.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/Makefile          |   5 +-
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S      | 430 ++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c |  36 +++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdsp.h              |   1 +
 | 
	
		
			
				|  |  | - 4 files changed, 471 insertions(+), 1 deletion(-)
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | - create mode 100644 lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/Makefile b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -index 715eed7..5b0edf0 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/Makefile
 | 
	
		
			
				|  |  | -@@ -14,6 +14,8 @@ ARMV6-OBJS-$(CONFIG_H264DSP)           += arm/startcode_armv6.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_FLAC_DECODER)            += arm/flacdsp_init_arm.o        \
 | 
	
		
			
				|  |  | -                                           arm/flacdsp_arm.o             \
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+OBJS-$(CONFIG_MLP_DECODER)             += arm/mlpdsp_init_arm.o         \
 | 
	
		
			
				|  |  | -+                                          arm/mlpdsp_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_MPEGAUDIODSP)            += arm/mpegaudiodsp_init_arm.o
 | 
	
		
			
				|  |  | - ARMV6-OBJS-$(CONFIG_MPEGAUDIODSP)      += arm/mpegaudiodsp_fixed_armv6.o
 | 
	
		
			
				|  |  | - ARMV6-OBJS-$(CONFIG_VC1_DECODER)       += arm/startcode_armv6.o
 | 
	
		
			
				|  |  | -@@ -21,6 +23,8 @@ OBJS-$(CONFIG_VC1_DECODER)             += arm/vc1dsp_init_arm.o
 | 
	
		
			
				|  |  | - ARMV6-OBJS-$(CONFIG_VC1_PARSER)        += arm/startcode_armv6.o
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_MPEGVIDEO)               += arm/mpegvideo_arm.o
 | 
	
		
			
				|  |  | -+OBJS-$(CONFIG_TRUEHD_DECODER)          += arm/mlpdsp_init_arm.o         \
 | 
	
		
			
				|  |  | -+                                          arm/mlpdsp_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VORBIS_DECODER)          += arm/vorbisdsp_init_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VP3DSP)                  += arm/vp3dsp_init_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_VP5_DECODER)             += arm/vp56dsp_init_arm.o
 | 
	
		
			
				|  |  | -@@ -34,7 +38,6 @@ OBJS-$(CONFIG_H264CHROMA)              += arm/h264chroma_init_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_H264DSP)                 += arm/h264dsp_init_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_H264PRED)                += arm/h264pred_init_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_H264QPEL)                += arm/h264qpel_init_arm.o
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_RV30_DECODER)            += arm/rv34dsp_init_arm.o
 | 
	
		
			
				|  |  | - OBJS-$(CONFIG_RV40_DECODER)            += arm/rv34dsp_init_arm.o        \
 | 
	
		
			
				|  |  | -                                           arm/rv40dsp_init_arm.o        \
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..114496f
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -@@ -0,0 +1,430 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ * Copyright (c) 2014 RISC OS Open Ltd
 | 
	
		
			
				|  |  | -+ * Author: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * This file is part of Libav.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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 Libav; if not, write to the Free Software
 | 
	
		
			
				|  |  | -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+// This code uses too many ARM-only tricks to easily assemble as Thumb
 | 
	
		
			
				|  |  | -+.arm
 | 
	
		
			
				|  |  | -+#undef CONFIG_THUMB
 | 
	
		
			
				|  |  | -+#define CONFIG_THUMB 0
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "libavutil/arm/asm.S"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define MAX_CHANNELS        8
 | 
	
		
			
				|  |  | -+#define MAX_FIR_ORDER       8
 | 
	
		
			
				|  |  | -+#define MAX_IIR_ORDER       4
 | 
	
		
			
				|  |  | -+#define MAX_RATEFACTOR      4
 | 
	
		
			
				|  |  | -+#define MAX_BLOCKSIZE       (40 * MAX_RATEFACTOR)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+PST     .req    a1
 | 
	
		
			
				|  |  | -+PCO     .req    a2
 | 
	
		
			
				|  |  | -+AC0     .req    a3
 | 
	
		
			
				|  |  | -+AC1     .req    a4
 | 
	
		
			
				|  |  | -+CO0     .req    v1
 | 
	
		
			
				|  |  | -+CO1     .req    v2
 | 
	
		
			
				|  |  | -+CO2     .req    v3
 | 
	
		
			
				|  |  | -+CO3     .req    v4
 | 
	
		
			
				|  |  | -+ST0     .req    v5
 | 
	
		
			
				|  |  | -+ST1     .req    v6
 | 
	
		
			
				|  |  | -+ST2     .req    sl
 | 
	
		
			
				|  |  | -+ST3     .req    fp
 | 
	
		
			
				|  |  | -+I       .req    ip
 | 
	
		
			
				|  |  | -+PSAMP   .req    lr
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+// Some macros that do loads/multiplies where the register number is determined
 | 
	
		
			
				|  |  | -+// from an assembly-time expression. Boy is GNU assembler's syntax ugly...
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro load  group, index, base, offset
 | 
	
		
			
				|  |  | -+       .altmacro
 | 
	
		
			
				|  |  | -+       load_ \group, %(\index), \base, \offset
 | 
	
		
			
				|  |  | -+       .noaltmacro
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro load_ group, index, base, offset
 | 
	
		
			
				|  |  | -+        ldr     \group\index, [\base, #\offset]
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro loadd  group, index, base, offset
 | 
	
		
			
				|  |  | -+       .altmacro
 | 
	
		
			
				|  |  | -+       loadd_ \group, %(\index), %(\index+1), \base, \offset
 | 
	
		
			
				|  |  | -+       .noaltmacro
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro loadd_ group, index0, index1, base, offset
 | 
	
		
			
				|  |  | -+A .if offset >= 256
 | 
	
		
			
				|  |  | -+A       ldr     \group\index0, [\base, #\offset]
 | 
	
		
			
				|  |  | -+A       ldr     \group\index1, [\base, #(\offset) + 4]
 | 
	
		
			
				|  |  | -+A .else
 | 
	
		
			
				|  |  | -+        ldrd    \group\index0, \group\index1, [\base, #\offset]
 | 
	
		
			
				|  |  | -+A .endif
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro multiply  index, accumulate, long
 | 
	
		
			
				|  |  | -+        .altmacro
 | 
	
		
			
				|  |  | -+        multiply_ %(\index), \accumulate, \long
 | 
	
		
			
				|  |  | -+        .noaltmacro
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro multiply_  index, accumulate, long
 | 
	
		
			
				|  |  | -+ .if \long
 | 
	
		
			
				|  |  | -+  .if \accumulate
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO\index, ST\index
 | 
	
		
			
				|  |  | -+  .else
 | 
	
		
			
				|  |  | -+        smull   AC0, AC1, CO\index, ST\index
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+ .else
 | 
	
		
			
				|  |  | -+  .if \accumulate
 | 
	
		
			
				|  |  | -+        mla     AC0, CO\index, ST\index, AC0
 | 
	
		
			
				|  |  | -+  .else
 | 
	
		
			
				|  |  | -+        mul     AC0, CO\index, ST\index
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+// A macro to update the load register number and load offsets
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro inc  howmany
 | 
	
		
			
				|  |  | -+  .set LOAD_REG, (LOAD_REG + \howmany) & 3
 | 
	
		
			
				|  |  | -+  .set OFFSET_CO, OFFSET_CO + 4 * \howmany
 | 
	
		
			
				|  |  | -+  .set OFFSET_ST, OFFSET_ST + 4 * \howmany
 | 
	
		
			
				|  |  | -+  .if FIR_REMAIN > 0
 | 
	
		
			
				|  |  | -+    .set FIR_REMAIN, FIR_REMAIN - \howmany
 | 
	
		
			
				|  |  | -+    .if FIR_REMAIN == 0
 | 
	
		
			
				|  |  | -+      .set OFFSET_CO, 4 * MAX_FIR_ORDER
 | 
	
		
			
				|  |  | -+      .set OFFSET_ST, 4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+  .elseif IIR_REMAIN > 0
 | 
	
		
			
				|  |  | -+    .set IIR_REMAIN, IIR_REMAIN - \howmany
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+// Macro to implement the inner loop for one specific combination of parameters
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro implement_filter  mask_minus1, shift_0, shift_8, iir_taps, fir_taps
 | 
	
		
			
				|  |  | -+  .set TOTAL_TAPS, \iir_taps + \fir_taps
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // Deal with register allocation...
 | 
	
		
			
				|  |  | -+  .set DEFINED_SHIFT, 0
 | 
	
		
			
				|  |  | -+  .set DEFINED_MASK, 0
 | 
	
		
			
				|  |  | -+  .set SHUFFLE_SHIFT, 0
 | 
	
		
			
				|  |  | -+  .set SHUFFLE_MASK, 0
 | 
	
		
			
				|  |  | -+  .set SPILL_SHIFT, 0
 | 
	
		
			
				|  |  | -+  .set SPILL_MASK, 0
 | 
	
		
			
				|  |  | -+  .if TOTAL_TAPS == 0
 | 
	
		
			
				|  |  | -+    // Little register pressure in this case - just keep MASK where it was
 | 
	
		
			
				|  |  | -+    .if !\mask_minus1
 | 
	
		
			
				|  |  | -+      MASK .req ST1
 | 
	
		
			
				|  |  | -+      .set DEFINED_MASK, 1
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+  .else
 | 
	
		
			
				|  |  | -+    .if \shift_0
 | 
	
		
			
				|  |  | -+      .if !\mask_minus1
 | 
	
		
			
				|  |  | -+        // AC1 is unused with shift 0
 | 
	
		
			
				|  |  | -+        MASK .req AC1
 | 
	
		
			
				|  |  | -+        .set DEFINED_MASK, 1
 | 
	
		
			
				|  |  | -+        .set SHUFFLE_MASK, 1
 | 
	
		
			
				|  |  | -+      .endif
 | 
	
		
			
				|  |  | -+    .elseif \shift_8
 | 
	
		
			
				|  |  | -+      .if !\mask_minus1
 | 
	
		
			
				|  |  | -+        .if TOTAL_TAPS <= 4
 | 
	
		
			
				|  |  | -+        // All coefficients are preloaded (so pointer not needed)
 | 
	
		
			
				|  |  | -+          MASK .req PCO
 | 
	
		
			
				|  |  | -+          .set DEFINED_MASK, 1
 | 
	
		
			
				|  |  | -+          .set SHUFFLE_MASK, 1
 | 
	
		
			
				|  |  | -+        .else
 | 
	
		
			
				|  |  | -+          .set SPILL_MASK, 1
 | 
	
		
			
				|  |  | -+        .endif
 | 
	
		
			
				|  |  | -+      .endif
 | 
	
		
			
				|  |  | -+    .else // shift not 0 or 8
 | 
	
		
			
				|  |  | -+      .if TOTAL_TAPS <= 3
 | 
	
		
			
				|  |  | -+        // All coefficients are preloaded, and at least one CO register is unused
 | 
	
		
			
				|  |  | -+        .if \fir_taps & 1
 | 
	
		
			
				|  |  | -+          SHIFT .req CO0
 | 
	
		
			
				|  |  | -+          .set DEFINED_SHIFT, 1
 | 
	
		
			
				|  |  | -+          .set SHUFFLE_SHIFT, 1
 | 
	
		
			
				|  |  | -+        .else
 | 
	
		
			
				|  |  | -+          SHIFT .req CO3
 | 
	
		
			
				|  |  | -+          .set DEFINED_SHIFT, 1
 | 
	
		
			
				|  |  | -+          .set SHUFFLE_SHIFT, 1
 | 
	
		
			
				|  |  | -+        .endif
 | 
	
		
			
				|  |  | -+        .if !\mask_minus1
 | 
	
		
			
				|  |  | -+          MASK .req PCO
 | 
	
		
			
				|  |  | -+          .set DEFINED_MASK, 1
 | 
	
		
			
				|  |  | -+          .set SHUFFLE_MASK, 1
 | 
	
		
			
				|  |  | -+        .endif
 | 
	
		
			
				|  |  | -+      .elseif TOTAL_TAPS == 4
 | 
	
		
			
				|  |  | -+        // All coefficients are preloaded
 | 
	
		
			
				|  |  | -+        SHIFT .req PCO
 | 
	
		
			
				|  |  | -+        .set DEFINED_SHIFT, 1
 | 
	
		
			
				|  |  | -+        .set SHUFFLE_SHIFT, 1
 | 
	
		
			
				|  |  | -+        .if !\mask_minus1
 | 
	
		
			
				|  |  | -+          .set SPILL_MASK, 1
 | 
	
		
			
				|  |  | -+        .endif
 | 
	
		
			
				|  |  | -+      .else
 | 
	
		
			
				|  |  | -+        .set SPILL_SHIFT, 1
 | 
	
		
			
				|  |  | -+        .if !\mask_minus1
 | 
	
		
			
				|  |  | -+          .set SPILL_MASK, 1
 | 
	
		
			
				|  |  | -+        .endif
 | 
	
		
			
				|  |  | -+      .endif
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if SPILL_SHIFT
 | 
	
		
			
				|  |  | -+    SHIFT .req ST0
 | 
	
		
			
				|  |  | -+    .set DEFINED_SHIFT, 1
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if SPILL_MASK
 | 
	
		
			
				|  |  | -+    MASK .req ST1
 | 
	
		
			
				|  |  | -+    .set DEFINED_MASK, 1
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        // Preload coefficients if possible
 | 
	
		
			
				|  |  | -+  .if TOTAL_TAPS <= 4
 | 
	
		
			
				|  |  | -+    .set OFFSET_CO, 0
 | 
	
		
			
				|  |  | -+    .if \fir_taps & 1
 | 
	
		
			
				|  |  | -+      .set LOAD_REG, 1
 | 
	
		
			
				|  |  | -+    .else
 | 
	
		
			
				|  |  | -+      .set LOAD_REG, 0
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+    .rept \fir_taps
 | 
	
		
			
				|  |  | -+        load    CO, LOAD_REG, PCO, OFFSET_CO
 | 
	
		
			
				|  |  | -+      .set LOAD_REG, (LOAD_REG + 1) & 3
 | 
	
		
			
				|  |  | -+      .set OFFSET_CO, OFFSET_CO + 4
 | 
	
		
			
				|  |  | -+    .endr
 | 
	
		
			
				|  |  | -+    .set OFFSET_CO, 4 * MAX_FIR_ORDER
 | 
	
		
			
				|  |  | -+    .rept \iir_taps
 | 
	
		
			
				|  |  | -+        load    CO, LOAD_REG, PCO, OFFSET_CO
 | 
	
		
			
				|  |  | -+      .set LOAD_REG, (LOAD_REG + 1) & 3
 | 
	
		
			
				|  |  | -+      .set OFFSET_CO, OFFSET_CO + 4
 | 
	
		
			
				|  |  | -+    .endr
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        // Move mask/shift to final positions if necessary
 | 
	
		
			
				|  |  | -+        // Need to do this after preloading, because in some cases we
 | 
	
		
			
				|  |  | -+        // reuse the coefficient pointer register
 | 
	
		
			
				|  |  | -+  .if SHUFFLE_SHIFT
 | 
	
		
			
				|  |  | -+        mov     SHIFT, ST0
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if SHUFFLE_MASK
 | 
	
		
			
				|  |  | -+        mov     MASK, ST1
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        // Begin loop
 | 
	
		
			
				|  |  | -+01:
 | 
	
		
			
				|  |  | -+  .if TOTAL_TAPS == 0
 | 
	
		
			
				|  |  | -+        // Things simplify a lot in this case
 | 
	
		
			
				|  |  | -+        // In fact this could be pipelined further if it's worth it...
 | 
	
		
			
				|  |  | -+        ldr     ST0, [PSAMP]
 | 
	
		
			
				|  |  | -+        subs    I, I, #1
 | 
	
		
			
				|  |  | -+    .if !\mask_minus1
 | 
	
		
			
				|  |  | -+        and     ST0, ST0, MASK
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+        str     ST0, [PST, #-4]!
 | 
	
		
			
				|  |  | -+        str     ST0, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)]
 | 
	
		
			
				|  |  | -+        str     ST0, [PSAMP], #4 * MAX_CHANNELS
 | 
	
		
			
				|  |  | -+        bne     01b
 | 
	
		
			
				|  |  | -+  .else
 | 
	
		
			
				|  |  | -+    .if \fir_taps & 1
 | 
	
		
			
				|  |  | -+      .set LOAD_REG, 1
 | 
	
		
			
				|  |  | -+    .else
 | 
	
		
			
				|  |  | -+      .set LOAD_REG, 0
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+    .set LOAD_BANK, 0
 | 
	
		
			
				|  |  | -+    .set FIR_REMAIN, \fir_taps
 | 
	
		
			
				|  |  | -+    .set IIR_REMAIN, \iir_taps
 | 
	
		
			
				|  |  | -+    .if FIR_REMAIN == 0 // only IIR terms
 | 
	
		
			
				|  |  | -+      .set OFFSET_CO, 4 * MAX_FIR_ORDER
 | 
	
		
			
				|  |  | -+      .set OFFSET_ST, 4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)
 | 
	
		
			
				|  |  | -+    .else
 | 
	
		
			
				|  |  | -+      .set OFFSET_CO, 0
 | 
	
		
			
				|  |  | -+      .set OFFSET_ST, 0
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+    .set MUL_REG, LOAD_REG
 | 
	
		
			
				|  |  | -+    .set COUNTER, 0
 | 
	
		
			
				|  |  | -+    .rept TOTAL_TAPS + 2
 | 
	
		
			
				|  |  | -+        // Do load(s)
 | 
	
		
			
				|  |  | -+     .if FIR_REMAIN != 0 || IIR_REMAIN != 0
 | 
	
		
			
				|  |  | -+      .if COUNTER == 0
 | 
	
		
			
				|  |  | -+       .if TOTAL_TAPS > 4
 | 
	
		
			
				|  |  | -+        load    CO, LOAD_REG, PCO, OFFSET_CO
 | 
	
		
			
				|  |  | -+       .endif
 | 
	
		
			
				|  |  | -+        load    ST, LOAD_REG, PST, OFFSET_ST
 | 
	
		
			
				|  |  | -+        inc     1
 | 
	
		
			
				|  |  | -+      .elseif COUNTER == 1 && (\fir_taps & 1) == 0
 | 
	
		
			
				|  |  | -+       .if TOTAL_TAPS > 4
 | 
	
		
			
				|  |  | -+        load    CO, LOAD_REG, PCO, OFFSET_CO
 | 
	
		
			
				|  |  | -+       .endif
 | 
	
		
			
				|  |  | -+        load    ST, LOAD_REG, PST, OFFSET_ST
 | 
	
		
			
				|  |  | -+        inc     1
 | 
	
		
			
				|  |  | -+      .elseif LOAD_BANK == 0
 | 
	
		
			
				|  |  | -+       .if TOTAL_TAPS > 4
 | 
	
		
			
				|  |  | -+        .if FIR_REMAIN == 0 && IIR_REMAIN == 1
 | 
	
		
			
				|  |  | -+        load    CO, LOAD_REG, PCO, OFFSET_CO
 | 
	
		
			
				|  |  | -+        .else
 | 
	
		
			
				|  |  | -+        loadd   CO, LOAD_REG, PCO, OFFSET_CO
 | 
	
		
			
				|  |  | -+        .endif
 | 
	
		
			
				|  |  | -+       .endif
 | 
	
		
			
				|  |  | -+       .set LOAD_BANK, 1
 | 
	
		
			
				|  |  | -+      .else
 | 
	
		
			
				|  |  | -+       .if FIR_REMAIN == 0 && IIR_REMAIN == 1
 | 
	
		
			
				|  |  | -+        load    ST, LOAD_REG, PST, OFFSET_ST
 | 
	
		
			
				|  |  | -+        inc     1
 | 
	
		
			
				|  |  | -+       .else
 | 
	
		
			
				|  |  | -+        loadd   ST, LOAD_REG, PST, OFFSET_ST
 | 
	
		
			
				|  |  | -+        inc     2
 | 
	
		
			
				|  |  | -+       .endif
 | 
	
		
			
				|  |  | -+       .set LOAD_BANK, 0
 | 
	
		
			
				|  |  | -+      .endif
 | 
	
		
			
				|  |  | -+     .endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        // Do interleaved multiplies, slightly delayed
 | 
	
		
			
				|  |  | -+     .if COUNTER >= 2
 | 
	
		
			
				|  |  | -+        multiply MUL_REG, COUNTER > 2, !\shift_0
 | 
	
		
			
				|  |  | -+      .set MUL_REG, (MUL_REG + 1) & 3
 | 
	
		
			
				|  |  | -+     .endif
 | 
	
		
			
				|  |  | -+     .set COUNTER, COUNTER + 1
 | 
	
		
			
				|  |  | -+    .endr
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        // Post-process the result of the multiplies
 | 
	
		
			
				|  |  | -+    .if SPILL_SHIFT
 | 
	
		
			
				|  |  | -+        ldr     SHIFT, [sp, #9*4 + 0*4]
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+    .if SPILL_MASK
 | 
	
		
			
				|  |  | -+        ldr     MASK, [sp, #9*4 + 1*4]
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+        ldr     ST2, [PSAMP]
 | 
	
		
			
				|  |  | -+        subs    I, I, #1
 | 
	
		
			
				|  |  | -+    .if \shift_8
 | 
	
		
			
				|  |  | -+        mov     AC0, AC0, lsr #8
 | 
	
		
			
				|  |  | -+        orr     AC0, AC0, AC1, lsl #24
 | 
	
		
			
				|  |  | -+    .elseif !\shift_0
 | 
	
		
			
				|  |  | -+        rsb     ST3, SHIFT, #32
 | 
	
		
			
				|  |  | -+        mov     AC0, AC0, lsr SHIFT
 | 
	
		
			
				|  |  | -+        orr     AC0, AC0, AC1, lsl ST3
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+    .if \mask_minus1
 | 
	
		
			
				|  |  | -+        add     ST3, ST2, AC0
 | 
	
		
			
				|  |  | -+    .else
 | 
	
		
			
				|  |  | -+        add     ST2, ST2, AC0
 | 
	
		
			
				|  |  | -+        and     ST3, ST2, MASK
 | 
	
		
			
				|  |  | -+        sub     ST2, ST3, AC0
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+        str     ST3, [PST, #-4]!
 | 
	
		
			
				|  |  | -+        str     ST2, [PST, #4 * (MAX_BLOCKSIZE + MAX_FIR_ORDER)]
 | 
	
		
			
				|  |  | -+        str     ST3, [PSAMP], #4 * MAX_CHANNELS
 | 
	
		
			
				|  |  | -+        bne     01b
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+        b       99f
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  .if DEFINED_SHIFT
 | 
	
		
			
				|  |  | -+    .unreq SHIFT
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if DEFINED_MASK
 | 
	
		
			
				|  |  | -+    .unreq MASK
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro switch_on_fir_taps  mask_minus1, shift_0, shift_8, iir_taps
 | 
	
		
			
				|  |  | -+        ldr     pc, [pc, a3, LSL #2] // firorder is in range 0-(8-iir_taps)
 | 
	
		
			
				|  |  | -+        .word   0
 | 
	
		
			
				|  |  | -+        .word   70f
 | 
	
		
			
				|  |  | -+        .word   71f
 | 
	
		
			
				|  |  | -+        .word   72f
 | 
	
		
			
				|  |  | -+        .word   73f
 | 
	
		
			
				|  |  | -+        .word   74f
 | 
	
		
			
				|  |  | -+        .word   75f
 | 
	
		
			
				|  |  | -+ .if \iir_taps <= 2
 | 
	
		
			
				|  |  | -+        .word   76f
 | 
	
		
			
				|  |  | -+  .if \iir_taps <= 1
 | 
	
		
			
				|  |  | -+        .word   77f
 | 
	
		
			
				|  |  | -+   .if \iir_taps == 0
 | 
	
		
			
				|  |  | -+        .word   78f
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+70:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 0
 | 
	
		
			
				|  |  | -+71:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 1
 | 
	
		
			
				|  |  | -+72:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 2
 | 
	
		
			
				|  |  | -+73:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 3
 | 
	
		
			
				|  |  | -+74:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 4
 | 
	
		
			
				|  |  | -+75:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 5
 | 
	
		
			
				|  |  | -+ .if \iir_taps <= 2
 | 
	
		
			
				|  |  | -+76:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 6
 | 
	
		
			
				|  |  | -+  .if \iir_taps <= 1
 | 
	
		
			
				|  |  | -+77:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 7
 | 
	
		
			
				|  |  | -+   .if \iir_taps == 0
 | 
	
		
			
				|  |  | -+78:     implement_filter  \mask_minus1, \shift_0, \shift_8, \iir_taps, 8
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro switch_on_iir_taps  mask_minus1, shift_0, shift_8
 | 
	
		
			
				|  |  | -+        ldr     pc, [pc, a4, LSL #2] // irorder is in range 0-3
 | 
	
		
			
				|  |  | -+        .word   0
 | 
	
		
			
				|  |  | -+        .word   60f
 | 
	
		
			
				|  |  | -+        .word   61f
 | 
	
		
			
				|  |  | -+        .word   62f
 | 
	
		
			
				|  |  | -+        .word   63f
 | 
	
		
			
				|  |  | -+60:     switch_on_fir_taps  \mask_minus1, \shift_0, \shift_8, 0
 | 
	
		
			
				|  |  | -+61:     switch_on_fir_taps  \mask_minus1, \shift_0, \shift_8, 1
 | 
	
		
			
				|  |  | -+62:     switch_on_fir_taps  \mask_minus1, \shift_0, \shift_8, 2
 | 
	
		
			
				|  |  | -+63:     switch_on_fir_taps  \mask_minus1, \shift_0, \shift_8, 3
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/* void ff_mlp_filter_channel_arm(int32_t *state, const int32_t *coeff,
 | 
	
		
			
				|  |  | -+ *                                int firorder, int iirorder,
 | 
	
		
			
				|  |  | -+ *                                unsigned int filter_shift, int32_t mask,
 | 
	
		
			
				|  |  | -+ *                                int blocksize, int32_t *sample_buffer);
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+function ff_mlp_filter_channel_arm, export=1
 | 
	
		
			
				|  |  | -+        push    {v1-fp,lr}
 | 
	
		
			
				|  |  | -+        add     v1, sp, #9*4 // point at arguments on stack
 | 
	
		
			
				|  |  | -+        ldm     v1, {ST0,ST1,I,PSAMP}
 | 
	
		
			
				|  |  | -+        cmp     ST1, #-1
 | 
	
		
			
				|  |  | -+        bne     30f
 | 
	
		
			
				|  |  | -+        movs    ST2, ST0, lsl #29 // shift is in range 0-15; we want to special-case 0 and 8
 | 
	
		
			
				|  |  | -+        bne     20f
 | 
	
		
			
				|  |  | -+        bcs     10f
 | 
	
		
			
				|  |  | -+        switch_on_iir_taps 1, 1, 0
 | 
	
		
			
				|  |  | -+10:     switch_on_iir_taps 1, 0, 1
 | 
	
		
			
				|  |  | -+20:     switch_on_iir_taps 1, 0, 0
 | 
	
		
			
				|  |  | -+30:     movs    ST2, ST0, lsl #29 // shift is in range 0-15; we want to special-case 0 and 8
 | 
	
		
			
				|  |  | -+        bne     50f
 | 
	
		
			
				|  |  | -+        bcs     40f
 | 
	
		
			
				|  |  | -+        switch_on_iir_taps 0, 1, 0
 | 
	
		
			
				|  |  | -+40:     switch_on_iir_taps 0, 0, 1
 | 
	
		
			
				|  |  | -+50:     switch_on_iir_taps 0, 0, 0
 | 
	
		
			
				|  |  | -+99:     pop     {v1-fp,pc}
 | 
	
		
			
				|  |  | -+endfunc
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        .unreq  PST
 | 
	
		
			
				|  |  | -+        .unreq  PCO
 | 
	
		
			
				|  |  | -+        .unreq  AC0
 | 
	
		
			
				|  |  | -+        .unreq  AC1
 | 
	
		
			
				|  |  | -+        .unreq  CO0
 | 
	
		
			
				|  |  | -+        .unreq  CO1
 | 
	
		
			
				|  |  | -+        .unreq  CO2
 | 
	
		
			
				|  |  | -+        .unreq  CO3
 | 
	
		
			
				|  |  | -+        .unreq  ST0
 | 
	
		
			
				|  |  | -+        .unreq  ST1
 | 
	
		
			
				|  |  | -+        .unreq  ST2
 | 
	
		
			
				|  |  | -+        .unreq  ST3
 | 
	
		
			
				|  |  | -+        .unreq  I
 | 
	
		
			
				|  |  | -+        .unreq  PSAMP
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..f0ea285
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -@@ -0,0 +1,36 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ * Copyright (c) 2014 RISC OS Open Ltd
 | 
	
		
			
				|  |  | -+ * Author: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * This file is part of Libav.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * Libav 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 Libav; if not, write to the Free Software
 | 
	
		
			
				|  |  | -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include <stdint.h>
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "libavutil/arm/cpu.h"
 | 
	
		
			
				|  |  | -+#include "libavutil/attributes.h"
 | 
	
		
			
				|  |  | -+#include "libavcodec/mlpdsp.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void ff_mlp_filter_channel_arm(int32_t *state, const int32_t *coeff,
 | 
	
		
			
				|  |  | -+                               int firorder, int iirorder,
 | 
	
		
			
				|  |  | -+                               unsigned int filter_shift, int32_t mask,
 | 
	
		
			
				|  |  | -+                               int blocksize, int32_t *sample_buffer);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+av_cold void ff_mlpdsp_init_arm(MLPDSPContext *c)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    c->mlp_filter_channel = ff_mlp_filter_channel_arm;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdsp.h b/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -index 84a8aa3..129bcfe 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -@@ -32,6 +32,7 @@ typedef struct MLPDSPContext {
 | 
	
		
			
				|  |  | - } MLPDSPContext;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void ff_mlpdsp_init(MLPDSPContext *c);
 | 
	
		
			
				|  |  | -+void ff_mlpdsp_init_arm(MLPDSPContext *c);
 | 
	
		
			
				|  |  | - void ff_mlpdsp_init_x86(MLPDSPContext *c);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif /* AVCODEC_MLPDSP_H */
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 904cb11e58484c5d0bca17b8c209916d106d2079 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 19 Mar 2014 17:48:54 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 09/94] truehd: break out part of rematrix_channels into
 | 
	
		
			
				|  |  | - platform-specific callback.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Verified with profiling that this doesn't have a measurable effect upon
 | 
	
		
			
				|  |  | -overall performance.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdec.c | 37 ++++++++++++-------------------------
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdsp.c | 35 ++++++++++++++++++++++++++++++++++-
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdsp.h | 23 +++++++++++++++++++++++
 | 
	
		
			
				|  |  | - 3 files changed, 69 insertions(+), 26 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdec.c b/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -index c763624..e9343a5 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -@@ -958,7 +958,7 @@ static void fill_noise_buffer(MLPDecodeContext *m, unsigned int substr)
 | 
	
		
			
				|  |  | - static void rematrix_channels(MLPDecodeContext *m, unsigned int substr)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -     SubStream *s = &m->substream[substr];
 | 
	
		
			
				|  |  | --    unsigned int mat, src_ch, i;
 | 
	
		
			
				|  |  | -+    unsigned int mat;
 | 
	
		
			
				|  |  | -     unsigned int maxchan;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     maxchan = s->max_matrix_channel;
 | 
	
		
			
				|  |  | -@@ -970,31 +970,18 @@ static void rematrix_channels(MLPDecodeContext *m, unsigned int substr)
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     for (mat = 0; mat < s->num_primitive_matrices; mat++) {
 | 
	
		
			
				|  |  | --        int matrix_noise_shift = s->matrix_noise_shift[mat];
 | 
	
		
			
				|  |  | -         unsigned int dest_ch = s->matrix_out_ch[mat];
 | 
	
		
			
				|  |  | --        int32_t mask = MSB_MASK(s->quant_step_size[dest_ch]);
 | 
	
		
			
				|  |  | --        int32_t *coeffs = s->matrix_coeff[mat];
 | 
	
		
			
				|  |  | --        int index  = s->num_primitive_matrices - mat;
 | 
	
		
			
				|  |  | --        int index2 = 2 * index + 1;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --        /* TODO: DSPContext? */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --        for (i = 0; i < s->blockpos; i++) {
 | 
	
		
			
				|  |  | --            int32_t bypassed_lsb = m->bypassed_lsbs[i][mat];
 | 
	
		
			
				|  |  | --            int32_t *samples = m->sample_buffer[i];
 | 
	
		
			
				|  |  | --            int64_t accum = 0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --            for (src_ch = 0; src_ch <= maxchan; src_ch++)
 | 
	
		
			
				|  |  | --                accum += (int64_t) samples[src_ch] * coeffs[src_ch];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --            if (matrix_noise_shift) {
 | 
	
		
			
				|  |  | --                index &= m->access_unit_size_pow2 - 1;
 | 
	
		
			
				|  |  | --                accum += m->noise_buffer[index] << (matrix_noise_shift + 7);
 | 
	
		
			
				|  |  | --                index += index2;
 | 
	
		
			
				|  |  | --            }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --            samples[dest_ch] = ((accum >> 14) & mask) + bypassed_lsb;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | -+        m->dsp.mlp_rematrix_channel(&m->sample_buffer[0][0],
 | 
	
		
			
				|  |  | -+                                    s->matrix_coeff[mat],
 | 
	
		
			
				|  |  | -+                                    &m->bypassed_lsbs[0][mat],
 | 
	
		
			
				|  |  | -+                                    m->noise_buffer,
 | 
	
		
			
				|  |  | -+                                    s->num_primitive_matrices - mat,
 | 
	
		
			
				|  |  | -+                                    dest_ch,
 | 
	
		
			
				|  |  | -+                                    s->blockpos,
 | 
	
		
			
				|  |  | -+                                    maxchan,
 | 
	
		
			
				|  |  | -+                                    s->matrix_noise_shift[mat],
 | 
	
		
			
				|  |  | -+                                    m->access_unit_size_pow2,
 | 
	
		
			
				|  |  | -+                                    MSB_MASK(s->quant_step_size[dest_ch]));
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdsp.c b/lib/ffmpeg/libavcodec/mlpdsp.c
 | 
	
		
			
				|  |  | -index 9a376e2..1f912fb 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdsp.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdsp.c
 | 
	
		
			
				|  |  | -@@ -56,9 +56,42 @@ static void ff_mlp_filter_channel(int32_t *state, const int32_t *coeff,
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void ff_mlpdsp_init(MLPDSPContext *c)
 | 
	
		
			
				|  |  | -+void ff_mlp_rematrix_channel(int32_t *samples,
 | 
	
		
			
				|  |  | -+                             const int32_t *coeffs,
 | 
	
		
			
				|  |  | -+                             const uint8_t *bypassed_lsbs,
 | 
	
		
			
				|  |  | -+                             const int8_t *noise_buffer,
 | 
	
		
			
				|  |  | -+                             int index,
 | 
	
		
			
				|  |  | -+                             unsigned int dest_ch,
 | 
	
		
			
				|  |  | -+                             uint16_t blockpos,
 | 
	
		
			
				|  |  | -+                             unsigned int maxchan,
 | 
	
		
			
				|  |  | -+                             int matrix_noise_shift,
 | 
	
		
			
				|  |  | -+                             int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -+                             int32_t mask)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    unsigned int src_ch, i;
 | 
	
		
			
				|  |  | -+    int index2 = 2 * index + 1;
 | 
	
		
			
				|  |  | -+    for (i = 0; i < blockpos; i++) {
 | 
	
		
			
				|  |  | -+        int64_t accum = 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        for (src_ch = 0; src_ch <= maxchan; src_ch++)
 | 
	
		
			
				|  |  | -+            accum += (int64_t) samples[src_ch] * coeffs[src_ch];
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        if (matrix_noise_shift) {
 | 
	
		
			
				|  |  | -+            index &= access_unit_size_pow2 - 1;
 | 
	
		
			
				|  |  | -+            accum += noise_buffer[index] << (matrix_noise_shift + 7);
 | 
	
		
			
				|  |  | -+            index += index2;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        samples[dest_ch] = ((accum >> 14) & mask) + *bypassed_lsbs;
 | 
	
		
			
				|  |  | -+        bypassed_lsbs += MAX_CHANNELS;
 | 
	
		
			
				|  |  | -+        samples += MAX_CHANNELS;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+av_cold void ff_mlpdsp_init(MLPDSPContext *c)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -     c->mlp_filter_channel = ff_mlp_filter_channel;
 | 
	
		
			
				|  |  | -+    c->mlp_rematrix_channel = ff_mlp_rematrix_channel;
 | 
	
		
			
				|  |  | -     if (ARCH_X86)
 | 
	
		
			
				|  |  | -         ff_mlpdsp_init_x86(c);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdsp.h b/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -index 129bcfe..f98e9be 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -@@ -24,11 +24,34 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include <stdint.h>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+void ff_mlp_rematrix_channel(int32_t *samples,
 | 
	
		
			
				|  |  | -+                             const int32_t *coeffs,
 | 
	
		
			
				|  |  | -+                             const uint8_t *bypassed_lsbs,
 | 
	
		
			
				|  |  | -+                             const int8_t *noise_buffer,
 | 
	
		
			
				|  |  | -+                             int index,
 | 
	
		
			
				|  |  | -+                             unsigned int dest_ch,
 | 
	
		
			
				|  |  | -+                             uint16_t blockpos,
 | 
	
		
			
				|  |  | -+                             unsigned int maxchan,
 | 
	
		
			
				|  |  | -+                             int matrix_noise_shift,
 | 
	
		
			
				|  |  | -+                             int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -+                             int32_t mask);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - typedef struct MLPDSPContext {
 | 
	
		
			
				|  |  | -     void (*mlp_filter_channel)(int32_t *state, const int32_t *coeff,
 | 
	
		
			
				|  |  | -                                int firorder, int iirorder,
 | 
	
		
			
				|  |  | -                                unsigned int filter_shift, int32_t mask,
 | 
	
		
			
				|  |  | -                                int blocksize, int32_t *sample_buffer);
 | 
	
		
			
				|  |  | -+    void (*mlp_rematrix_channel)(int32_t *samples,
 | 
	
		
			
				|  |  | -+                                 const int32_t *coeffs,
 | 
	
		
			
				|  |  | -+                                 const uint8_t *bypassed_lsbs,
 | 
	
		
			
				|  |  | -+                                 const int8_t *noise_buffer,
 | 
	
		
			
				|  |  | -+                                 int index,
 | 
	
		
			
				|  |  | -+                                 unsigned int dest_ch,
 | 
	
		
			
				|  |  | -+                                 uint16_t blockpos,
 | 
	
		
			
				|  |  | -+                                 unsigned int maxchan,
 | 
	
		
			
				|  |  | -+                                 int matrix_noise_shift,
 | 
	
		
			
				|  |  | -+                                 int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -+                                 int32_t mask);
 | 
	
		
			
				|  |  | - } MLPDSPContext;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void ff_mlpdsp_init(MLPDSPContext *c);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 0bb8daacca4b35d716addbc591fec43fd4fe6467 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 19 Mar 2014 17:49:48 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 10/94] truehd: add hand-scheduled ARM asm version of
 | 
	
		
			
				|  |  | - ff_mlp_rematrix_channel.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Profiling results for overall audio decode and the rematrix_channels function
 | 
	
		
			
				|  |  | -in particular are as follows:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -              Before          After
 | 
	
		
			
				|  |  | -              Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -6:2 total     370.8  17.0     348.8  20.1    99.9%       +6.3%
 | 
	
		
			
				|  |  | -6:2 function  46.4   8.4      45.8   6.6     18.0%       +1.2%  (insignificant)
 | 
	
		
			
				|  |  | -8:2 total     343.2  19.0     339.1  15.4    54.7%       +1.2%  (insignificant)
 | 
	
		
			
				|  |  | -8:2 function  38.9   3.9      40.2   6.9     52.4%       -3.2%  (insignificant)
 | 
	
		
			
				|  |  | -6:6 total     658.4  15.7     604.6  20.8    100.0%      +8.9%
 | 
	
		
			
				|  |  | -6:6 function  109.0  8.7      59.5   5.4     100.0%      +83.3%
 | 
	
		
			
				|  |  | -8:8 total     896.2  24.5     766.4  17.6    100.0%      +16.9%
 | 
	
		
			
				|  |  | -8:8 function  223.4  12.8     93.8   5.0     100.0%      +138.3%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The assembly version has also been tested with a fuzz tester to ensure that
 | 
	
		
			
				|  |  | -any combinations of inputs not exercised by my available test streams still
 | 
	
		
			
				|  |  | -generate mathematically identical results to the C version.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S      | 231 ++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c |  12 ++
 | 
	
		
			
				|  |  | - 2 files changed, 243 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -index 114496f..10008fe 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -@@ -428,3 +428,234 @@ endfunc
 | 
	
		
			
				|  |  | -         .unreq  ST3
 | 
	
		
			
				|  |  | -         .unreq  I
 | 
	
		
			
				|  |  | -         .unreq  PSAMP
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/********************************************************************/
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+PSA     .req    a1 // samples
 | 
	
		
			
				|  |  | -+PCO     .req    a2 // coeffs
 | 
	
		
			
				|  |  | -+PBL     .req    a3 // bypassed_lsbs
 | 
	
		
			
				|  |  | -+INDEX   .req    a4
 | 
	
		
			
				|  |  | -+CO0     .req    v1
 | 
	
		
			
				|  |  | -+CO1     .req    v2
 | 
	
		
			
				|  |  | -+CO2     .req    v3
 | 
	
		
			
				|  |  | -+CO3     .req    v4
 | 
	
		
			
				|  |  | -+SA0     .req    v5
 | 
	
		
			
				|  |  | -+SA1     .req    v6
 | 
	
		
			
				|  |  | -+SA2     .req    sl
 | 
	
		
			
				|  |  | -+SA3     .req    fp
 | 
	
		
			
				|  |  | -+AC0     .req    ip
 | 
	
		
			
				|  |  | -+AC1     .req    lr
 | 
	
		
			
				|  |  | -+NOISE   .req    SA0
 | 
	
		
			
				|  |  | -+LSB     .req    SA1
 | 
	
		
			
				|  |  | -+DCH     .req    SA2 // dest_ch
 | 
	
		
			
				|  |  | -+MASK    .req    SA3
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    // INDEX is used as follows:
 | 
	
		
			
				|  |  | -+    // bits 0..6   index2 (values up to 17, but wider so that we can
 | 
	
		
			
				|  |  | -+    //               add to index field without needing to mask)
 | 
	
		
			
				|  |  | -+    // bits 7..14  i (values up to 160)
 | 
	
		
			
				|  |  | -+    // bit 15      underflow detect for i
 | 
	
		
			
				|  |  | -+    // bits 25..31 (if access_unit_size_pow2 == 128)  \ index
 | 
	
		
			
				|  |  | -+    // bits 26..31 (if access_unit_size_pow2 == 64)   /
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro implement_rematrix  shift, index_mask, mask_minus1, maxchan
 | 
	
		
			
				|  |  | -+    .if \maxchan == 1
 | 
	
		
			
				|  |  | -+        // We can just leave the coefficients in registers in this case
 | 
	
		
			
				|  |  | -+        ldrd    CO0, CO1, [PCO]
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+1:
 | 
	
		
			
				|  |  | -+    .if \maxchan == 1
 | 
	
		
			
				|  |  | -+        ldrd    SA0, SA1, [PSA]
 | 
	
		
			
				|  |  | -+        smull   AC0, AC1, CO0, SA0
 | 
	
		
			
				|  |  | -+    .elseif \maxchan == 5
 | 
	
		
			
				|  |  | -+        ldr     CO0, [PCO, #0]
 | 
	
		
			
				|  |  | -+        ldr     SA0, [PSA, #0]
 | 
	
		
			
				|  |  | -+        ldr     CO1, [PCO, #4]
 | 
	
		
			
				|  |  | -+        ldr     SA1, [PSA, #4]
 | 
	
		
			
				|  |  | -+        ldrd    CO2, CO3, [PCO, #8]
 | 
	
		
			
				|  |  | -+        smull   AC0, AC1, CO0, SA0
 | 
	
		
			
				|  |  | -+        ldrd    SA2, SA3, [PSA, #8]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO1, SA1
 | 
	
		
			
				|  |  | -+        ldrd    CO0, CO1, [PCO, #16]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO2, SA2
 | 
	
		
			
				|  |  | -+        ldrd    SA0, SA1, [PSA, #16]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO3, SA3
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO0, SA0
 | 
	
		
			
				|  |  | -+    .else // \maxchan == 7
 | 
	
		
			
				|  |  | -+        ldr     CO2, [PCO, #0]
 | 
	
		
			
				|  |  | -+        ldr     SA2, [PSA, #0]
 | 
	
		
			
				|  |  | -+        ldr     CO3, [PCO, #4]
 | 
	
		
			
				|  |  | -+        ldr     SA3, [PSA, #4]
 | 
	
		
			
				|  |  | -+        ldrd    CO0, CO1, [PCO, #8]
 | 
	
		
			
				|  |  | -+        smull   AC0, AC1, CO2, SA2
 | 
	
		
			
				|  |  | -+        ldrd    SA0, SA1, [PSA, #8]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO3, SA3
 | 
	
		
			
				|  |  | -+        ldrd    CO2, CO3, [PCO, #16]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO0, SA0
 | 
	
		
			
				|  |  | -+        ldrd    SA2, SA3, [PSA, #16]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO1, SA1
 | 
	
		
			
				|  |  | -+        ldrd    CO0, CO1, [PCO, #24]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO2, SA2
 | 
	
		
			
				|  |  | -+        ldrd    SA0, SA1, [PSA, #24]
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO3, SA3
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO0, SA0
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+        ldm     sp, {NOISE, DCH, MASK}
 | 
	
		
			
				|  |  | -+        smlal   AC0, AC1, CO1, SA1
 | 
	
		
			
				|  |  | -+    .if \shift != 0
 | 
	
		
			
				|  |  | -+      .if \index_mask == 63
 | 
	
		
			
				|  |  | -+        add     NOISE, NOISE, INDEX, lsr #32-6
 | 
	
		
			
				|  |  | -+        ldrb    LSB, [PBL], #MAX_CHANNELS
 | 
	
		
			
				|  |  | -+        ldrsb   NOISE, [NOISE]
 | 
	
		
			
				|  |  | -+        add     INDEX, INDEX, INDEX, lsl #32-6
 | 
	
		
			
				|  |  | -+      .else // \index_mask == 127
 | 
	
		
			
				|  |  | -+        add     NOISE, NOISE, INDEX, lsr #32-7
 | 
	
		
			
				|  |  | -+        ldrb    LSB, [PBL], #MAX_CHANNELS
 | 
	
		
			
				|  |  | -+        ldrsb   NOISE, [NOISE]
 | 
	
		
			
				|  |  | -+        add     INDEX, INDEX, INDEX, lsl #32-7
 | 
	
		
			
				|  |  | -+      .endif
 | 
	
		
			
				|  |  | -+        sub     INDEX, INDEX, #1<<7
 | 
	
		
			
				|  |  | -+        adds    AC0, AC0, NOISE, lsl #\shift + 7
 | 
	
		
			
				|  |  | -+        adc     AC1, AC1, NOISE, asr #31
 | 
	
		
			
				|  |  | -+    .else
 | 
	
		
			
				|  |  | -+        ldrb    LSB, [PBL], #MAX_CHANNELS
 | 
	
		
			
				|  |  | -+        sub     INDEX, INDEX, #1<<7
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+        add     PSA, PSA, #MAX_CHANNELS*4
 | 
	
		
			
				|  |  | -+        mov     AC0, AC0, lsr #14
 | 
	
		
			
				|  |  | -+        orr     AC0, AC0, AC1, lsl #18
 | 
	
		
			
				|  |  | -+    .if !\mask_minus1
 | 
	
		
			
				|  |  | -+        and     AC0, AC0, MASK
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+        add     AC0, AC0, LSB
 | 
	
		
			
				|  |  | -+        tst     INDEX, #1<<15
 | 
	
		
			
				|  |  | -+        str     AC0, [PSA, DCH, lsl #2]  // DCH is precompensated for the early increment of PSA
 | 
	
		
			
				|  |  | -+        beq     1b
 | 
	
		
			
				|  |  | -+        b       98f
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro switch_on_maxchan  shift, index_mask, mask_minus1
 | 
	
		
			
				|  |  | -+        cmp     v4, #5
 | 
	
		
			
				|  |  | -+        blo     51f
 | 
	
		
			
				|  |  | -+        beq     50f
 | 
	
		
			
				|  |  | -+        implement_rematrix  \shift, \index_mask, \mask_minus1, 7
 | 
	
		
			
				|  |  | -+50:     implement_rematrix  \shift, \index_mask, \mask_minus1, 5
 | 
	
		
			
				|  |  | -+51:     implement_rematrix  \shift, \index_mask, \mask_minus1, 1
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro switch_on_mask  shift, index_mask
 | 
	
		
			
				|  |  | -+        cmp     sl, #-1
 | 
	
		
			
				|  |  | -+        bne     40f
 | 
	
		
			
				|  |  | -+        switch_on_maxchan  \shift, \index_mask, 1
 | 
	
		
			
				|  |  | -+40:     switch_on_maxchan  \shift, \index_mask, 0
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro switch_on_au_size  shift
 | 
	
		
			
				|  |  | -+  .if \shift == 0
 | 
	
		
			
				|  |  | -+        switch_on_mask  \shift, undefined
 | 
	
		
			
				|  |  | -+  .else
 | 
	
		
			
				|  |  | -+        teq     v6, #64
 | 
	
		
			
				|  |  | -+        bne     30f
 | 
	
		
			
				|  |  | -+        orr     INDEX, INDEX, v1, lsl #32-6
 | 
	
		
			
				|  |  | -+        switch_on_mask  \shift, 63
 | 
	
		
			
				|  |  | -+30:     orr     INDEX, INDEX, v1, lsl #32-7
 | 
	
		
			
				|  |  | -+        switch_on_mask  \shift, 127
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/* void ff_mlp_rematrix_channel_arm(int32_t *samples,
 | 
	
		
			
				|  |  | -+ *                                  const int32_t *coeffs,
 | 
	
		
			
				|  |  | -+ *                                  const uint8_t *bypassed_lsbs,
 | 
	
		
			
				|  |  | -+ *                                  const int8_t *noise_buffer,
 | 
	
		
			
				|  |  | -+ *                                  int index,
 | 
	
		
			
				|  |  | -+ *                                  unsigned int dest_ch,
 | 
	
		
			
				|  |  | -+ *                                  uint16_t blockpos,
 | 
	
		
			
				|  |  | -+ *                                  unsigned int maxchan,
 | 
	
		
			
				|  |  | -+ *                                  int matrix_noise_shift,
 | 
	
		
			
				|  |  | -+ *                                  int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -+ *                                  int32_t mask);
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+function ff_mlp_rematrix_channel_arm, export=1
 | 
	
		
			
				|  |  | -+        push    {v1-fp,lr}
 | 
	
		
			
				|  |  | -+        add     v1, sp, #9*4 // point at arguments on stack
 | 
	
		
			
				|  |  | -+        ldm     v1, {v1-sl}
 | 
	
		
			
				|  |  | -+        teq     v4, #1
 | 
	
		
			
				|  |  | -+        teqne   v4, #5
 | 
	
		
			
				|  |  | -+        teqne   v4, #7
 | 
	
		
			
				|  |  | -+        bne     99f
 | 
	
		
			
				|  |  | -+        teq     v6, #64
 | 
	
		
			
				|  |  | -+        teqne   v6, #128
 | 
	
		
			
				|  |  | -+        bne     99f
 | 
	
		
			
				|  |  | -+        sub     v2, v2, #MAX_CHANNELS
 | 
	
		
			
				|  |  | -+        push    {a4,v2,sl}          // initialise NOISE,DCH,MASK; make sp dword-aligned
 | 
	
		
			
				|  |  | -+        movs    INDEX, v3, lsl #7
 | 
	
		
			
				|  |  | -+        beq     98f                 // just in case, do nothing if blockpos = 0
 | 
	
		
			
				|  |  | -+        subs    INDEX, INDEX, #1<<7 // offset by 1 so we borrow at the right time
 | 
	
		
			
				|  |  | -+        adc     lr, v1, v1          // calculate index2 (C was set by preceding subs)
 | 
	
		
			
				|  |  | -+        orr     INDEX, INDEX, lr
 | 
	
		
			
				|  |  | -+        // Switch on matrix_noise_shift: values 0 and 1 are
 | 
	
		
			
				|  |  | -+        // disproportionately common so do those in a form the branch
 | 
	
		
			
				|  |  | -+        // predictor can accelerate. Values can only go up to 15.
 | 
	
		
			
				|  |  | -+        cmp     v5, #1
 | 
	
		
			
				|  |  | -+        beq     11f
 | 
	
		
			
				|  |  | -+        blo     10f
 | 
	
		
			
				|  |  | -+        ldr     pc, [pc, v5, lsl #2]
 | 
	
		
			
				|  |  | -+        .word   0
 | 
	
		
			
				|  |  | -+        .word   0
 | 
	
		
			
				|  |  | -+        .word   0
 | 
	
		
			
				|  |  | -+        .word   12f
 | 
	
		
			
				|  |  | -+        .word   13f
 | 
	
		
			
				|  |  | -+        .word   14f
 | 
	
		
			
				|  |  | -+        .word   15f
 | 
	
		
			
				|  |  | -+        .word   16f
 | 
	
		
			
				|  |  | -+        .word   17f
 | 
	
		
			
				|  |  | -+        .word   18f
 | 
	
		
			
				|  |  | -+        .word   19f
 | 
	
		
			
				|  |  | -+        .word   20f
 | 
	
		
			
				|  |  | -+        .word   21f
 | 
	
		
			
				|  |  | -+        .word   22f
 | 
	
		
			
				|  |  | -+        .word   23f
 | 
	
		
			
				|  |  | -+        .word   24f
 | 
	
		
			
				|  |  | -+        .word   25f
 | 
	
		
			
				|  |  | -+10:     switch_on_au_size  0
 | 
	
		
			
				|  |  | -+11:     switch_on_au_size  1
 | 
	
		
			
				|  |  | -+12:     switch_on_au_size  2
 | 
	
		
			
				|  |  | -+13:     switch_on_au_size  3
 | 
	
		
			
				|  |  | -+14:     switch_on_au_size  4
 | 
	
		
			
				|  |  | -+15:     switch_on_au_size  5
 | 
	
		
			
				|  |  | -+16:     switch_on_au_size  6
 | 
	
		
			
				|  |  | -+17:     switch_on_au_size  7
 | 
	
		
			
				|  |  | -+18:     switch_on_au_size  8
 | 
	
		
			
				|  |  | -+19:     switch_on_au_size  9
 | 
	
		
			
				|  |  | -+20:     switch_on_au_size  10
 | 
	
		
			
				|  |  | -+21:     switch_on_au_size  11
 | 
	
		
			
				|  |  | -+22:     switch_on_au_size  12
 | 
	
		
			
				|  |  | -+23:     switch_on_au_size  13
 | 
	
		
			
				|  |  | -+24:     switch_on_au_size  14
 | 
	
		
			
				|  |  | -+25:     switch_on_au_size  15
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+98:     add     sp, sp, #3*4
 | 
	
		
			
				|  |  | -+        pop     {v1-fp,pc}
 | 
	
		
			
				|  |  | -+99:     // Can't handle these parameters, drop back to C
 | 
	
		
			
				|  |  | -+        pop     {v1-fp,lr}
 | 
	
		
			
				|  |  | -+        b       X(ff_mlp_rematrix_channel)
 | 
	
		
			
				|  |  | -+endfunc
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        .unreq  PSA
 | 
	
		
			
				|  |  | -+        .unreq  PCO
 | 
	
		
			
				|  |  | -+        .unreq  PBL
 | 
	
		
			
				|  |  | -+        .unreq  INDEX
 | 
	
		
			
				|  |  | -+        .unreq  CO0
 | 
	
		
			
				|  |  | -+        .unreq  CO1
 | 
	
		
			
				|  |  | -+        .unreq  CO2
 | 
	
		
			
				|  |  | -+        .unreq  CO3
 | 
	
		
			
				|  |  | -+        .unreq  SA0
 | 
	
		
			
				|  |  | -+        .unreq  SA1
 | 
	
		
			
				|  |  | -+        .unreq  SA2
 | 
	
		
			
				|  |  | -+        .unreq  SA3
 | 
	
		
			
				|  |  | -+        .unreq  AC0
 | 
	
		
			
				|  |  | -+        .unreq  AC1
 | 
	
		
			
				|  |  | -+        .unreq  NOISE
 | 
	
		
			
				|  |  | -+        .unreq  LSB
 | 
	
		
			
				|  |  | -+        .unreq  DCH
 | 
	
		
			
				|  |  | -+        .unreq  MASK
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -index f0ea285..268dfdd 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -@@ -29,8 +29,20 @@ void ff_mlp_filter_channel_arm(int32_t *state, const int32_t *coeff,
 | 
	
		
			
				|  |  | -                                int firorder, int iirorder,
 | 
	
		
			
				|  |  | -                                unsigned int filter_shift, int32_t mask,
 | 
	
		
			
				|  |  | -                                int blocksize, int32_t *sample_buffer);
 | 
	
		
			
				|  |  | -+void ff_mlp_rematrix_channel_arm(int32_t *samples,
 | 
	
		
			
				|  |  | -+                                 const int32_t *coeffs,
 | 
	
		
			
				|  |  | -+                                 const uint8_t *bypassed_lsbs,
 | 
	
		
			
				|  |  | -+                                 const int8_t *noise_buffer,
 | 
	
		
			
				|  |  | -+                                 int index,
 | 
	
		
			
				|  |  | -+                                 unsigned int dest_ch,
 | 
	
		
			
				|  |  | -+                                 uint16_t blockpos,
 | 
	
		
			
				|  |  | -+                                 unsigned int maxchan,
 | 
	
		
			
				|  |  | -+                                 int matrix_noise_shift,
 | 
	
		
			
				|  |  | -+                                 int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -+                                 int32_t mask);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - av_cold void ff_mlpdsp_init_arm(MLPDSPContext *c)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -     c->mlp_filter_channel = ff_mlp_filter_channel_arm;
 | 
	
		
			
				|  |  | -+    c->mlp_rematrix_channel = ff_mlp_rematrix_channel_arm;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 034e1a8920aec0fa36ffc7da8f63e48c68364e15 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 19 Mar 2014 17:50:36 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 11/94] truehd: tune VLC decoding for ARM.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Profiling on a Raspberry Pi revealed the best performance to correspond
 | 
	
		
			
				|  |  | -with VLC_BITS = 5. Results for overall audio decode and the get_vlc2 function
 | 
	
		
			
				|  |  | -in particular are as follows:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -              Before          After
 | 
	
		
			
				|  |  | -              Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -6:2 total     348.8  20.1     339.6  15.1    88.8%       +2.7%  (insignificant)
 | 
	
		
			
				|  |  | -6:2 function  38.1   8.1      26.4   4.1     100.0%      +44.5%
 | 
	
		
			
				|  |  | -8:2 total     339.1  15.4     324.5  15.5    99.4%       +4.5%
 | 
	
		
			
				|  |  | -8:2 function  33.8   7.0      27.3   5.6     99.7%       +23.6%
 | 
	
		
			
				|  |  | -6:6 total     604.6  20.8     572.8  20.6    100.0%      +5.6%
 | 
	
		
			
				|  |  | -6:6 function  95.8   8.4      68.9   8.2     100.0%      +39.1%
 | 
	
		
			
				|  |  | -8:8 total     766.4  17.6     741.5  21.2    100.0%      +3.4%
 | 
	
		
			
				|  |  | -8:8 function  106.0  11.4     86.1   9.9     100.0%      +23.1%
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdec.c | 13 ++++++++++---
 | 
	
		
			
				|  |  | - 1 file changed, 10 insertions(+), 3 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdec.c b/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -index e9343a5..a998dac 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -@@ -36,9 +36,16 @@
 | 
	
		
			
				|  |  | - #include "mlp_parser.h"
 | 
	
		
			
				|  |  | - #include "mlpdsp.h"
 | 
	
		
			
				|  |  | - #include "mlp.h"
 | 
	
		
			
				|  |  | -+#include "config.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - /** number of bits used for VLC lookup - longest Huffman code is 9 */
 | 
	
		
			
				|  |  | -+#if ARCH_ARM == 1
 | 
	
		
			
				|  |  | -+#define VLC_BITS            5
 | 
	
		
			
				|  |  | -+#define VLC_STATIC_SIZE     64
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | - #define VLC_BITS            9
 | 
	
		
			
				|  |  | -+#define VLC_STATIC_SIZE     512
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - typedef struct SubStream {
 | 
	
		
			
				|  |  | -     /// Set if a valid restart header has been read. Otherwise the substream cannot be decoded.
 | 
	
		
			
				|  |  | -@@ -190,13 +197,13 @@ static av_cold void init_static(void)
 | 
	
		
			
				|  |  | -     if (!huff_vlc[0].bits) {
 | 
	
		
			
				|  |  | -         INIT_VLC_STATIC(&huff_vlc[0], VLC_BITS, 18,
 | 
	
		
			
				|  |  | -                     &ff_mlp_huffman_tables[0][0][1], 2, 1,
 | 
	
		
			
				|  |  | --                    &ff_mlp_huffman_tables[0][0][0], 2, 1, 512);
 | 
	
		
			
				|  |  | -+                    &ff_mlp_huffman_tables[0][0][0], 2, 1, VLC_STATIC_SIZE);
 | 
	
		
			
				|  |  | -         INIT_VLC_STATIC(&huff_vlc[1], VLC_BITS, 16,
 | 
	
		
			
				|  |  | -                     &ff_mlp_huffman_tables[1][0][1], 2, 1,
 | 
	
		
			
				|  |  | --                    &ff_mlp_huffman_tables[1][0][0], 2, 1, 512);
 | 
	
		
			
				|  |  | -+                    &ff_mlp_huffman_tables[1][0][0], 2, 1, VLC_STATIC_SIZE);
 | 
	
		
			
				|  |  | -         INIT_VLC_STATIC(&huff_vlc[2], VLC_BITS, 15,
 | 
	
		
			
				|  |  | -                     &ff_mlp_huffman_tables[2][0][1], 2, 1,
 | 
	
		
			
				|  |  | --                    &ff_mlp_huffman_tables[2][0][0], 2, 1, 512);
 | 
	
		
			
				|  |  | -+                    &ff_mlp_huffman_tables[2][0][0], 2, 1, VLC_STATIC_SIZE);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     ff_mlp_init_crc();
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 25ab0401ebb7f035bcf7291452e6772a9c7b233a Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 19 Mar 2014 17:54:07 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 12/94] truehd: break out part of output_data into
 | 
	
		
			
				|  |  | - platform-specific callback.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Verified with profiling that this doesn't have a measurable effect upon
 | 
	
		
			
				|  |  | -overall performance.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdec.c | 40 +++++++++++++++++++++++-----------------
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdsp.c | 36 ++++++++++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/mlpdsp.h | 22 ++++++++++++++++++++++
 | 
	
		
			
				|  |  | - 3 files changed, 81 insertions(+), 17 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdec.c b/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -index a998dac..6d7c803 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdec.c
 | 
	
		
			
				|  |  | -@@ -359,6 +359,10 @@ static int read_major_sync(MLPDecodeContext *m, GetBitContext *gb)
 | 
	
		
			
				|  |  | -         m->avctx->sample_fmt = AV_SAMPLE_FMT_S32;
 | 
	
		
			
				|  |  | -     else
 | 
	
		
			
				|  |  | -         m->avctx->sample_fmt = AV_SAMPLE_FMT_S16;
 | 
	
		
			
				|  |  | -+    m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(m->substream[m->max_decoded_substream].max_matrix_channel,
 | 
	
		
			
				|  |  | -+                                                           m->avctx->sample_fmt == AV_SAMPLE_FMT_S32,
 | 
	
		
			
				|  |  | -+                                                           m->substream[m->max_decoded_substream].ch_assign,
 | 
	
		
			
				|  |  | -+                                                           m->substream[m->max_decoded_substream].output_shift);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     m->params_valid = 1;
 | 
	
		
			
				|  |  | -     for (substr = 0; substr < MAX_SUBSTREAMS; substr++)
 | 
	
		
			
				|  |  | -@@ -553,6 +557,10 @@ static int read_restart_header(MLPDecodeContext *m, GetBitContext *gbp,
 | 
	
		
			
				|  |  | -     if (substr == m->max_decoded_substream) {
 | 
	
		
			
				|  |  | -         m->avctx->channels       = s->max_matrix_channel + 1;
 | 
	
		
			
				|  |  | -         m->avctx->channel_layout = s->ch_layout;
 | 
	
		
			
				|  |  | -+        m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(s->max_matrix_channel,
 | 
	
		
			
				|  |  | -+                                                               m->avctx->sample_fmt == AV_SAMPLE_FMT_S32,
 | 
	
		
			
				|  |  | -+                                                               s->ch_assign,
 | 
	
		
			
				|  |  | -+                                                               s->output_shift);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         if (m->avctx->codec_id == AV_CODEC_ID_MLP && m->needs_reordering) {
 | 
	
		
			
				|  |  | -             if (m->avctx->channel_layout == (AV_CH_LAYOUT_QUAD|AV_CH_LOW_FREQUENCY) ||
 | 
	
		
			
				|  |  | -@@ -798,9 +806,15 @@ static int read_decoding_params(MLPDecodeContext *m, GetBitContext *gbp,
 | 
	
		
			
				|  |  | -                 return ret;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (s->param_presence_flags & PARAM_OUTSHIFT)
 | 
	
		
			
				|  |  | --        if (get_bits1(gbp))
 | 
	
		
			
				|  |  | -+        if (get_bits1(gbp)) {
 | 
	
		
			
				|  |  | -             for (ch = 0; ch <= s->max_matrix_channel; ch++)
 | 
	
		
			
				|  |  | -                 s->output_shift[ch] = get_sbits(gbp, 4);
 | 
	
		
			
				|  |  | -+            if (substr == m->max_decoded_substream)
 | 
	
		
			
				|  |  | -+                m->dsp.mlp_pack_output = m->dsp.mlp_select_pack_output(s->max_matrix_channel,
 | 
	
		
			
				|  |  | -+                                                                       m->avctx->sample_fmt == AV_SAMPLE_FMT_S32,
 | 
	
		
			
				|  |  | -+                                                                       s->ch_assign,
 | 
	
		
			
				|  |  | -+                                                                       s->output_shift);
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (s->param_presence_flags & PARAM_QUANTSTEP)
 | 
	
		
			
				|  |  | -         if (get_bits1(gbp))
 | 
	
		
			
				|  |  | -@@ -999,9 +1013,6 @@ static int output_data(MLPDecodeContext *m, unsigned int substr,
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -     AVCodecContext *avctx = m->avctx;
 | 
	
		
			
				|  |  | -     SubStream *s = &m->substream[substr];
 | 
	
		
			
				|  |  | --    unsigned int i, out_ch = 0;
 | 
	
		
			
				|  |  | --    int32_t *data_32;
 | 
	
		
			
				|  |  | --    int16_t *data_16;
 | 
	
		
			
				|  |  | -     int ret;
 | 
	
		
			
				|  |  | -     int is32 = (m->avctx->sample_fmt == AV_SAMPLE_FMT_S32);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -1021,19 +1032,14 @@ static int output_data(MLPDecodeContext *m, unsigned int substr,
 | 
	
		
			
				|  |  | -         av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
 | 
	
		
			
				|  |  | -         return ret;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    data_32 = (int32_t *)frame->data[0];
 | 
	
		
			
				|  |  | --    data_16 = (int16_t *)frame->data[0];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    for (i = 0; i < s->blockpos; i++) {
 | 
	
		
			
				|  |  | --        for (out_ch = 0; out_ch <= s->max_matrix_channel; out_ch++) {
 | 
	
		
			
				|  |  | --            int mat_ch = s->ch_assign[out_ch];
 | 
	
		
			
				|  |  | --            int32_t sample = m->sample_buffer[i][mat_ch]
 | 
	
		
			
				|  |  | --                          << s->output_shift[mat_ch];
 | 
	
		
			
				|  |  | --            s->lossless_check_data ^= (sample & 0xffffff) << mat_ch;
 | 
	
		
			
				|  |  | --            if (is32) *data_32++ = sample << 8;
 | 
	
		
			
				|  |  | --            else      *data_16++ = sample >> 8;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    s->lossless_check_data = m->dsp.mlp_pack_output(s->lossless_check_data,
 | 
	
		
			
				|  |  | -+                                                    m->sample_buffer,
 | 
	
		
			
				|  |  | -+                                                    frame->data[0],
 | 
	
		
			
				|  |  | -+                                                    s->blockpos,
 | 
	
		
			
				|  |  | -+                                                    s->max_matrix_channel,
 | 
	
		
			
				|  |  | -+                                                    is32,
 | 
	
		
			
				|  |  | -+                                                    s->ch_assign,
 | 
	
		
			
				|  |  | -+                                                    s->output_shift);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     *got_frame_ptr = 1;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdsp.c b/lib/ffmpeg/libavcodec/mlpdsp.c
 | 
	
		
			
				|  |  | -index 1f912fb..2bb5cec 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdsp.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdsp.c
 | 
	
		
			
				|  |  | -@@ -88,10 +88,46 @@ void ff_mlp_rematrix_channel(int32_t *samples,
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+static int32_t (*mlp_select_pack_output(uint8_t max_matrix_channel,
 | 
	
		
			
				|  |  | -+                                        int is32,
 | 
	
		
			
				|  |  | -+                                        uint8_t *ch_assign,
 | 
	
		
			
				|  |  | -+                                        int8_t *output_shift))(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    return ff_mlp_pack_output;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int32_t ff_mlp_pack_output(int32_t lossless_check_data,
 | 
	
		
			
				|  |  | -+                           int32_t (*sample_buffer)[MAX_CHANNELS],
 | 
	
		
			
				|  |  | -+                           void *data,
 | 
	
		
			
				|  |  | -+                           uint16_t blockpos,
 | 
	
		
			
				|  |  | -+                           uint8_t max_matrix_channel,
 | 
	
		
			
				|  |  | -+                           int is32,
 | 
	
		
			
				|  |  | -+                           uint8_t *ch_assign,
 | 
	
		
			
				|  |  | -+                           int8_t *output_shift)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    unsigned int i, out_ch = 0;
 | 
	
		
			
				|  |  | -+    int32_t *data_32 = (int32_t *)data;
 | 
	
		
			
				|  |  | -+    int16_t *data_16 = (int16_t *)data;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    for (i = 0; i < blockpos; i++) {
 | 
	
		
			
				|  |  | -+        for (out_ch = 0; out_ch <= max_matrix_channel; out_ch++) {
 | 
	
		
			
				|  |  | -+            int mat_ch = ch_assign[out_ch];
 | 
	
		
			
				|  |  | -+            int32_t sample = sample_buffer[i][mat_ch]
 | 
	
		
			
				|  |  | -+                          << output_shift[mat_ch];
 | 
	
		
			
				|  |  | -+            lossless_check_data ^= (sample & 0xffffff) << mat_ch;
 | 
	
		
			
				|  |  | -+            if (is32) *data_32++ = sample << 8;
 | 
	
		
			
				|  |  | -+            else      *data_16++ = sample >> 8;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    return lossless_check_data;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - av_cold void ff_mlpdsp_init(MLPDSPContext *c)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -     c->mlp_filter_channel = ff_mlp_filter_channel;
 | 
	
		
			
				|  |  | -     c->mlp_rematrix_channel = ff_mlp_rematrix_channel;
 | 
	
		
			
				|  |  | -+    c->mlp_select_pack_output = mlp_select_pack_output;
 | 
	
		
			
				|  |  | -+    c->mlp_pack_output = ff_mlp_pack_output;
 | 
	
		
			
				|  |  | -     if (ARCH_X86)
 | 
	
		
			
				|  |  | -         ff_mlpdsp_init_x86(c);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/mlpdsp.h b/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -index f98e9be..5bc901f 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/mlpdsp.h
 | 
	
		
			
				|  |  | -@@ -23,6 +23,7 @@
 | 
	
		
			
				|  |  | - #define AVCODEC_MLPDSP_H
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include <stdint.h>
 | 
	
		
			
				|  |  | -+#include "mlp.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void ff_mlp_rematrix_channel(int32_t *samples,
 | 
	
		
			
				|  |  | -                              const int32_t *coeffs,
 | 
	
		
			
				|  |  | -@@ -36,6 +37,15 @@ void ff_mlp_rematrix_channel(int32_t *samples,
 | 
	
		
			
				|  |  | -                              int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -                              int32_t mask);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+int32_t ff_mlp_pack_output(int32_t lossless_check_data,
 | 
	
		
			
				|  |  | -+                           int32_t (*sample_buffer)[MAX_CHANNELS],
 | 
	
		
			
				|  |  | -+                           void *data,
 | 
	
		
			
				|  |  | -+                           uint16_t blockpos,
 | 
	
		
			
				|  |  | -+                           uint8_t max_matrix_channel,
 | 
	
		
			
				|  |  | -+                           int is32,
 | 
	
		
			
				|  |  | -+                           uint8_t *ch_assign,
 | 
	
		
			
				|  |  | -+                           int8_t *output_shift);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - typedef struct MLPDSPContext {
 | 
	
		
			
				|  |  | -     void (*mlp_filter_channel)(int32_t *state, const int32_t *coeff,
 | 
	
		
			
				|  |  | -                                int firorder, int iirorder,
 | 
	
		
			
				|  |  | -@@ -52,6 +62,18 @@ typedef struct MLPDSPContext {
 | 
	
		
			
				|  |  | -                                  int matrix_noise_shift,
 | 
	
		
			
				|  |  | -                                  int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -                                  int32_t mask);
 | 
	
		
			
				|  |  | -+    int32_t (*(*mlp_select_pack_output)(uint8_t max_matrix_channel,
 | 
	
		
			
				|  |  | -+                                        int is32,
 | 
	
		
			
				|  |  | -+                                        uint8_t *ch_assign,
 | 
	
		
			
				|  |  | -+                                        int8_t *output_shift))(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *);
 | 
	
		
			
				|  |  | -+    int32_t (*mlp_pack_output)(int32_t lossless_check_data,
 | 
	
		
			
				|  |  | -+                               int32_t (*sample_buffer)[MAX_CHANNELS],
 | 
	
		
			
				|  |  | -+                               void *data,
 | 
	
		
			
				|  |  | -+                               uint16_t blockpos,
 | 
	
		
			
				|  |  | -+                               uint8_t max_matrix_channel,
 | 
	
		
			
				|  |  | -+                               int is32,
 | 
	
		
			
				|  |  | -+                               uint8_t *ch_assign,
 | 
	
		
			
				|  |  | -+                               int8_t *output_shift);
 | 
	
		
			
				|  |  | - } MLPDSPContext;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void ff_mlpdsp_init(MLPDSPContext *c);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From bdefac00779c5601816f949353d9bbeb3b199611 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 19 Mar 2014 17:54:59 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 13/94] truehd: add hand-scheduled ARM asm version of
 | 
	
		
			
				|  |  | - ff_mlp_pack_output.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Profiling results for overall decode and the output_data function in
 | 
	
		
			
				|  |  | -particular are as follows:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -              Before          After
 | 
	
		
			
				|  |  | -              Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -6:2 total     339.6  15.1     329.3  16.0    95.8%       +3.1%  (insignificant)
 | 
	
		
			
				|  |  | -6:2 function  24.6   6.0      9.9    3.1     100.0%      +148.5%
 | 
	
		
			
				|  |  | -8:2 total     324.5  15.5     323.6  14.3    15.2%       +0.3%  (insignificant)
 | 
	
		
			
				|  |  | -8:2 function  20.4   3.9      9.9    3.4     100.0%      +104.7%
 | 
	
		
			
				|  |  | -6:6 total     572.8  20.6     539.9  24.2    100.0%      +6.1%
 | 
	
		
			
				|  |  | -6:6 function  54.5   5.6      16.0   3.8     100.0%      +240.9%
 | 
	
		
			
				|  |  | -8:8 total     741.5  21.2     702.5  18.5    100.0%      +5.6%
 | 
	
		
			
				|  |  | -8:8 function  63.9   7.6      18.4   4.8     100.0%      +247.3%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The assembly version has also been tested with a fuzz tester to ensure that
 | 
	
		
			
				|  |  | -any combinations of inputs not exercised by my available test streams still
 | 
	
		
			
				|  |  | -generate mathematically identical results to the C version.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S      | 503 ++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c |  64 ++++
 | 
	
		
			
				|  |  | - 2 files changed, 567 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -index 10008fe..338d323 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_arm.S
 | 
	
		
			
				|  |  | -@@ -98,6 +98,26 @@ A .endif
 | 
	
		
			
				|  |  | -  .endif
 | 
	
		
			
				|  |  | - .endm
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+.macro loadregoffsh2  group, index, base, offgroup, offindex
 | 
	
		
			
				|  |  | -+       .altmacro
 | 
	
		
			
				|  |  | -+       loadregoffsh2_ \group, %(\index), \base, \offgroup, %(\offindex)
 | 
	
		
			
				|  |  | -+       .noaltmacro
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro loadregoffsh2_ group, index, base, offgroup, offindex
 | 
	
		
			
				|  |  | -+        ldr     \group\index, [\base, \offgroup\offindex, lsl #2]
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro eorlslreg  check, data, group, index
 | 
	
		
			
				|  |  | -+        .altmacro
 | 
	
		
			
				|  |  | -+        eorlslreg_ \check, \data, \group, %(\index)
 | 
	
		
			
				|  |  | -+        .noaltmacro
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro eorlslreg_ check, data, group, index
 | 
	
		
			
				|  |  | -+        eor     \check, \check, \data, lsl \group\index
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - // A macro to update the load register number and load offsets
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - .macro inc  howmany
 | 
	
		
			
				|  |  | -@@ -659,3 +679,486 @@ endfunc
 | 
	
		
			
				|  |  | -         .unreq  LSB
 | 
	
		
			
				|  |  | -         .unreq  DCH
 | 
	
		
			
				|  |  | -         .unreq  MASK
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/********************************************************************/
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro decr_modulo var, by, modulus
 | 
	
		
			
				|  |  | -+ .set \var, \var - \by
 | 
	
		
			
				|  |  | -+ .if \var == 0
 | 
	
		
			
				|  |  | -+  .set \var, \modulus
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .macro load_group1  size, channels, r0, r1, r2, r3, pointer_dead=0
 | 
	
		
			
				|  |  | -+  .if \size == 2
 | 
	
		
			
				|  |  | -+        ldrd    \r0, \r1, [IN], #(\size + 8 - \channels) * 4
 | 
	
		
			
				|  |  | -+  .else // size == 4
 | 
	
		
			
				|  |  | -+   .if IDX1 > 4 || \channels==8
 | 
	
		
			
				|  |  | -+        ldm     IN!, {\r0, \r1, \r2, \r3}
 | 
	
		
			
				|  |  | -+   .else
 | 
	
		
			
				|  |  | -+        ldm     IN, {\r0, \r1, \r2, \r3}
 | 
	
		
			
				|  |  | -+    .if !\pointer_dead
 | 
	
		
			
				|  |  | -+        add     IN, IN, #(4 + 8 - \channels) * 4
 | 
	
		
			
				|  |  | -+     .endif
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+        decr_modulo IDX1, \size, \channels
 | 
	
		
			
				|  |  | -+ .endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .macro load_group2  size, channels, r0, r1, r2, r3, pointer_dead=0
 | 
	
		
			
				|  |  | -+  .if \size == 2
 | 
	
		
			
				|  |  | -+   .if IDX1 > 2
 | 
	
		
			
				|  |  | -+        ldm     IN!, {\r2, \r3}
 | 
	
		
			
				|  |  | -+   .else
 | 
	
		
			
				|  |  | -+//A   .ifc \r2, ip
 | 
	
		
			
				|  |  | -+//A    .if \pointer_dead
 | 
	
		
			
				|  |  | -+//A       ldm     IN, {\r2, \r3}
 | 
	
		
			
				|  |  | -+//A    .else
 | 
	
		
			
				|  |  | -+//A       ldr     \r2, [IN], #4
 | 
	
		
			
				|  |  | -+//A       ldr     \r3, [IN], #(\size - 1 + 8 - \channels) * 4
 | 
	
		
			
				|  |  | -+//A    .endif
 | 
	
		
			
				|  |  | -+//A   .else
 | 
	
		
			
				|  |  | -+        ldrd    \r2, \r3, [IN], #(\size + 8 - \channels) * 4
 | 
	
		
			
				|  |  | -+//A   .endif
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+        decr_modulo IDX1, \size, \channels
 | 
	
		
			
				|  |  | -+ .endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro implement_pack  inorder, channels, shift
 | 
	
		
			
				|  |  | -+.if \inorder
 | 
	
		
			
				|  |  | -+.ifc \shift, mixed
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CHECK   .req    a1
 | 
	
		
			
				|  |  | -+IN      .req    a2
 | 
	
		
			
				|  |  | -+OUT     .req    a3
 | 
	
		
			
				|  |  | -+COUNT   .req    a4
 | 
	
		
			
				|  |  | -+DAT0    .req    v1
 | 
	
		
			
				|  |  | -+DAT1    .req    v2
 | 
	
		
			
				|  |  | -+DAT2    .req    v3
 | 
	
		
			
				|  |  | -+DAT3    .req    v4
 | 
	
		
			
				|  |  | -+SHIFT0  .req    v5
 | 
	
		
			
				|  |  | -+SHIFT1  .req    v6
 | 
	
		
			
				|  |  | -+SHIFT2  .req    sl
 | 
	
		
			
				|  |  | -+SHIFT3  .req    fp
 | 
	
		
			
				|  |  | -+SHIFT4  .req    ip
 | 
	
		
			
				|  |  | -+SHIFT5  .req    lr
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .macro output4words
 | 
	
		
			
				|  |  | -+  .set SIZE_GROUP1, IDX1
 | 
	
		
			
				|  |  | -+  .if SIZE_GROUP1 > 4
 | 
	
		
			
				|  |  | -+   .set SIZE_GROUP1, 4
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .set SIZE_GROUP2, 4 - SIZE_GROUP1
 | 
	
		
			
				|  |  | -+        load_group1  SIZE_GROUP1, \channels, DAT0, DAT1, DAT2, DAT3
 | 
	
		
			
				|  |  | -+        load_group2  SIZE_GROUP2, \channels, DAT0, DAT1, DAT2, DAT3
 | 
	
		
			
				|  |  | -+   .if \channels == 2
 | 
	
		
			
				|  |  | -+        lsl     DAT0, SHIFT0
 | 
	
		
			
				|  |  | -+        lsl     DAT1, SHIFT1
 | 
	
		
			
				|  |  | -+        lsl     DAT2, SHIFT0
 | 
	
		
			
				|  |  | -+        lsl     DAT3, SHIFT1
 | 
	
		
			
				|  |  | -+   .elseif \channels == 6
 | 
	
		
			
				|  |  | -+    .if IDX2 == 6
 | 
	
		
			
				|  |  | -+        lsl     DAT0, SHIFT0
 | 
	
		
			
				|  |  | -+        lsl     DAT1, SHIFT1
 | 
	
		
			
				|  |  | -+        lsl     DAT2, SHIFT2
 | 
	
		
			
				|  |  | -+        lsl     DAT3, SHIFT3
 | 
	
		
			
				|  |  | -+    .elseif IDX2 == 2
 | 
	
		
			
				|  |  | -+        lsl     DAT0, SHIFT4
 | 
	
		
			
				|  |  | -+        lsl     DAT1, SHIFT5
 | 
	
		
			
				|  |  | -+        lsl     DAT2, SHIFT0
 | 
	
		
			
				|  |  | -+        lsl     DAT3, SHIFT1
 | 
	
		
			
				|  |  | -+    .else // IDX2 == 4
 | 
	
		
			
				|  |  | -+        lsl     DAT0, SHIFT2
 | 
	
		
			
				|  |  | -+        lsl     DAT1, SHIFT3
 | 
	
		
			
				|  |  | -+        lsl     DAT2, SHIFT4
 | 
	
		
			
				|  |  | -+        lsl     DAT3, SHIFT5
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+   .elseif \channels == 8
 | 
	
		
			
				|  |  | -+    .if IDX2 == 8
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT0, SHIFT4, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT1, SHIFT4, ror #8
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT2, SHIFT4, ror #16
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT3, SHIFT4, ror #24
 | 
	
		
			
				|  |  | -+    .else
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT0, SHIFT5, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT1, SHIFT5, ror #8
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT2, SHIFT5, ror #16
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT3, SHIFT5, ror #24
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+        lsl     DAT0, SHIFT0
 | 
	
		
			
				|  |  | -+        lsl     DAT1, SHIFT1
 | 
	
		
			
				|  |  | -+        lsl     DAT2, SHIFT2
 | 
	
		
			
				|  |  | -+        lsl     DAT3, SHIFT3
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT0, lsr #8 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT1, lsr #7 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+   decr_modulo IDX2, 2, \channels
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT2, lsr #8 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT3, lsr #7 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+   decr_modulo IDX2, 2, \channels
 | 
	
		
			
				|  |  | -+        stm     OUT!, {DAT0 - DAT3}
 | 
	
		
			
				|  |  | -+ .endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .set WORDS_PER_LOOP, \channels  // calculate LCM (channels, 4)
 | 
	
		
			
				|  |  | -+ .if (WORDS_PER_LOOP % 2) == 0
 | 
	
		
			
				|  |  | -+  .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .if (WORDS_PER_LOOP % 2) == 0
 | 
	
		
			
				|  |  | -+  .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .set WORDS_PER_LOOP, WORDS_PER_LOOP * 4
 | 
	
		
			
				|  |  | -+ .set SAMPLES_PER_LOOP, WORDS_PER_LOOP / \channels
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+function ff_mlp_pack_output_inorder_\channels\()ch_mixedshift_arm, export=1
 | 
	
		
			
				|  |  | -+ .if SAMPLES_PER_LOOP > 1
 | 
	
		
			
				|  |  | -+        tst     COUNT, #SAMPLES_PER_LOOP - 1  // always seems to be in practice
 | 
	
		
			
				|  |  | -+        bne     X(ff_mlp_pack_output)         // but just in case, branch to C implementation if not
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+        teq     COUNT, #0
 | 
	
		
			
				|  |  | -+        bxeq    lr
 | 
	
		
			
				|  |  | -+        push    {v1-v6,sl,fp,lr}
 | 
	
		
			
				|  |  | -+        ldr     SHIFT0, [sp, #(9+3)*4]  // get output_shift from stack
 | 
	
		
			
				|  |  | -+        ldr     SHIFT1, =0x08080808
 | 
	
		
			
				|  |  | -+        ldr     SHIFT4, [SHIFT0]
 | 
	
		
			
				|  |  | -+ .if \channels == 2
 | 
	
		
			
				|  |  | -+        uadd8   SHIFT4, SHIFT4, SHIFT1 // increase all shifts by 8
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT0, SHIFT4, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT1, SHIFT4, ror #8
 | 
	
		
			
				|  |  | -+ .else
 | 
	
		
			
				|  |  | -+        ldr     SHIFT5, [SHIFT0, #4]
 | 
	
		
			
				|  |  | -+        uadd8   SHIFT4, SHIFT4, SHIFT1 // increase all shifts by 8
 | 
	
		
			
				|  |  | -+        uadd8   SHIFT5, SHIFT5, SHIFT1
 | 
	
		
			
				|  |  | -+  .if \channels == 6
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT0, SHIFT4, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT1, SHIFT4, ror #8
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT2, SHIFT4, ror #16
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT3, SHIFT4, ror #24
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT4, SHIFT5, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    SHIFT5, SHIFT5, ror #8
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .set IDX1, \channels
 | 
	
		
			
				|  |  | -+ .set IDX2, \channels
 | 
	
		
			
				|  |  | -+0:
 | 
	
		
			
				|  |  | -+ .rept WORDS_PER_LOOP / 4
 | 
	
		
			
				|  |  | -+        output4words
 | 
	
		
			
				|  |  | -+ .endr
 | 
	
		
			
				|  |  | -+        subs    COUNT, COUNT, #SAMPLES_PER_LOOP
 | 
	
		
			
				|  |  | -+        bne     0b
 | 
	
		
			
				|  |  | -+        pop     {v1-v6,sl,fp,pc}
 | 
	
		
			
				|  |  | -+        .ltorg
 | 
	
		
			
				|  |  | -+endfunc
 | 
	
		
			
				|  |  | -+ .purgem output4words
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        .unreq  CHECK
 | 
	
		
			
				|  |  | -+        .unreq  IN
 | 
	
		
			
				|  |  | -+        .unreq  OUT
 | 
	
		
			
				|  |  | -+        .unreq  COUNT
 | 
	
		
			
				|  |  | -+        .unreq  DAT0
 | 
	
		
			
				|  |  | -+        .unreq  DAT1
 | 
	
		
			
				|  |  | -+        .unreq  DAT2
 | 
	
		
			
				|  |  | -+        .unreq  DAT3
 | 
	
		
			
				|  |  | -+        .unreq  SHIFT0
 | 
	
		
			
				|  |  | -+        .unreq  SHIFT1
 | 
	
		
			
				|  |  | -+        .unreq  SHIFT2
 | 
	
		
			
				|  |  | -+        .unreq  SHIFT3
 | 
	
		
			
				|  |  | -+        .unreq  SHIFT4
 | 
	
		
			
				|  |  | -+        .unreq  SHIFT5
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.else // not mixed
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CHECK   .req    a1
 | 
	
		
			
				|  |  | -+IN      .req    a2
 | 
	
		
			
				|  |  | -+OUT     .req    a3
 | 
	
		
			
				|  |  | -+COUNT   .req    a4
 | 
	
		
			
				|  |  | -+DAT0    .req    v1
 | 
	
		
			
				|  |  | -+DAT1    .req    v2
 | 
	
		
			
				|  |  | -+DAT2    .req    v3
 | 
	
		
			
				|  |  | -+DAT3    .req    v4
 | 
	
		
			
				|  |  | -+DAT4    .req    v5
 | 
	
		
			
				|  |  | -+DAT5    .req    v6
 | 
	
		
			
				|  |  | -+DAT6    .req    sl // use these rather than the otherwise unused
 | 
	
		
			
				|  |  | -+DAT7    .req    fp // ip and lr so that we can load them usinf LDRD
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .macro output4words  tail, head, r0, r1, r2, r3, r4, r5, r6, r7, pointer_dead=0
 | 
	
		
			
				|  |  | -+  .if \head
 | 
	
		
			
				|  |  | -+   .set SIZE_GROUP1, IDX1
 | 
	
		
			
				|  |  | -+   .if SIZE_GROUP1 > 4
 | 
	
		
			
				|  |  | -+    .set SIZE_GROUP1, 4
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+   .set SIZE_GROUP2, 4 - SIZE_GROUP1
 | 
	
		
			
				|  |  | -+        load_group1  SIZE_GROUP1, \channels, \r0, \r1, \r2, \r3, \pointer_dead
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if \tail
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, \r4, lsr #8 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, \r5, lsr #7 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+   decr_modulo IDX2, 2, \channels
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if \head
 | 
	
		
			
				|  |  | -+        load_group2  SIZE_GROUP2, \channels, \r0, \r1, \r2, \r3, \pointer_dead
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if \tail
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, \r6, lsr #8 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, \r7, lsr #7 - (\channels - IDX2)
 | 
	
		
			
				|  |  | -+   decr_modulo IDX2, 2, \channels
 | 
	
		
			
				|  |  | -+        stm     OUT!, {\r4, \r5, \r6, \r7}
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if \head
 | 
	
		
			
				|  |  | -+        lsl     \r0, #8 + \shift
 | 
	
		
			
				|  |  | -+        lsl     \r1, #8 + \shift
 | 
	
		
			
				|  |  | -+        lsl     \r2, #8 + \shift
 | 
	
		
			
				|  |  | -+        lsl     \r3, #8 + \shift
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+ .endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .set WORDS_PER_LOOP, \channels  // calculate LCM (channels, 8)
 | 
	
		
			
				|  |  | -+ .if (WORDS_PER_LOOP % 2) == 0
 | 
	
		
			
				|  |  | -+  .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .if (WORDS_PER_LOOP % 2) == 0
 | 
	
		
			
				|  |  | -+  .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .if (WORDS_PER_LOOP % 2) == 0
 | 
	
		
			
				|  |  | -+  .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .set WORDS_PER_LOOP, WORDS_PER_LOOP * 8
 | 
	
		
			
				|  |  | -+ .set SAMPLES_PER_LOOP, WORDS_PER_LOOP / \channels
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+function ff_mlp_pack_output_inorder_\channels\()ch_\shift\()shift_arm, export=1
 | 
	
		
			
				|  |  | -+ .if SAMPLES_PER_LOOP > 1
 | 
	
		
			
				|  |  | -+        tst     COUNT, #SAMPLES_PER_LOOP - 1  // always seems to be in practice
 | 
	
		
			
				|  |  | -+        bne     X(ff_mlp_pack_output)         // but just in case, branch to C implementation if not
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+        subs    COUNT, COUNT, #SAMPLES_PER_LOOP
 | 
	
		
			
				|  |  | -+        bxlo    lr
 | 
	
		
			
				|  |  | -+        push    {v1-v6,sl,fp,lr}
 | 
	
		
			
				|  |  | -+ .set IDX1, \channels
 | 
	
		
			
				|  |  | -+ .set IDX2, \channels
 | 
	
		
			
				|  |  | -+        output4words  0, 1, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
 | 
	
		
			
				|  |  | -+0:      beq     1f
 | 
	
		
			
				|  |  | -+ .rept WORDS_PER_LOOP / 8
 | 
	
		
			
				|  |  | -+        output4words  1, 1, DAT4, DAT5, DAT6, DAT7, DAT0, DAT1, DAT2, DAT3
 | 
	
		
			
				|  |  | -+        output4words  1, 1, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
 | 
	
		
			
				|  |  | -+ .endr
 | 
	
		
			
				|  |  | -+        subs    COUNT, COUNT, #SAMPLES_PER_LOOP
 | 
	
		
			
				|  |  | -+        bne     0b
 | 
	
		
			
				|  |  | -+1:
 | 
	
		
			
				|  |  | -+ .rept WORDS_PER_LOOP / 8 - 1
 | 
	
		
			
				|  |  | -+        output4words  1, 1, DAT4, DAT5, DAT6, DAT7, DAT0, DAT1, DAT2, DAT3
 | 
	
		
			
				|  |  | -+        output4words  1, 1, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
 | 
	
		
			
				|  |  | -+ .endr
 | 
	
		
			
				|  |  | -+        output4words  1, 1, DAT4, DAT5, DAT6, DAT7, DAT0, DAT1, DAT2, DAT3, pointer_dead=1
 | 
	
		
			
				|  |  | -+        output4words  1, 0, DAT0, DAT1, DAT2, DAT3, DAT4, DAT5, DAT6, DAT7
 | 
	
		
			
				|  |  | -+        pop     {v1-v6,sl,fp,pc}
 | 
	
		
			
				|  |  | -+endfunc
 | 
	
		
			
				|  |  | -+ .purgem output4words
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        .unreq  CHECK
 | 
	
		
			
				|  |  | -+        .unreq  IN
 | 
	
		
			
				|  |  | -+        .unreq  OUT
 | 
	
		
			
				|  |  | -+        .unreq  COUNT
 | 
	
		
			
				|  |  | -+        .unreq  DAT0
 | 
	
		
			
				|  |  | -+        .unreq  DAT1
 | 
	
		
			
				|  |  | -+        .unreq  DAT2
 | 
	
		
			
				|  |  | -+        .unreq  DAT3
 | 
	
		
			
				|  |  | -+        .unreq  DAT4
 | 
	
		
			
				|  |  | -+        .unreq  DAT5
 | 
	
		
			
				|  |  | -+        .unreq  DAT6
 | 
	
		
			
				|  |  | -+        .unreq  DAT7
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.endif // mixed
 | 
	
		
			
				|  |  | -+.else // not inorder
 | 
	
		
			
				|  |  | -+.ifc \shift, mixed
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+// This case not currently handled
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.else // not mixed
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CHECK   .req    a1
 | 
	
		
			
				|  |  | -+IN      .req    a2
 | 
	
		
			
				|  |  | -+OUT     .req    a3
 | 
	
		
			
				|  |  | -+COUNT   .req    a4
 | 
	
		
			
				|  |  | -+DAT0    .req    v1
 | 
	
		
			
				|  |  | -+DAT1    .req    v2
 | 
	
		
			
				|  |  | -+DAT2    .req    v3
 | 
	
		
			
				|  |  | -+DAT3    .req    v4
 | 
	
		
			
				|  |  | -+CHAN0   .req    v5
 | 
	
		
			
				|  |  | -+CHAN1   .req    v6
 | 
	
		
			
				|  |  | -+CHAN2   .req    sl
 | 
	
		
			
				|  |  | -+CHAN3   .req    fp
 | 
	
		
			
				|  |  | -+CHAN4   .req    ip
 | 
	
		
			
				|  |  | -+CHAN5   .req    lr
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .macro output4words
 | 
	
		
			
				|  |  | -+  .if \channels == 8
 | 
	
		
			
				|  |  | -+   .if IDX1 == 8
 | 
	
		
			
				|  |  | -+        uxtb    CHAN0, CHAN4, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    CHAN1, CHAN4, ror #8
 | 
	
		
			
				|  |  | -+        uxtb    CHAN2, CHAN4, ror #16
 | 
	
		
			
				|  |  | -+        uxtb    CHAN3, CHAN4, ror #24
 | 
	
		
			
				|  |  | -+   .else
 | 
	
		
			
				|  |  | -+        uxtb    CHAN0, CHAN5, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    CHAN1, CHAN5, ror #8
 | 
	
		
			
				|  |  | -+        uxtb    CHAN2, CHAN5, ror #16
 | 
	
		
			
				|  |  | -+        uxtb    CHAN3, CHAN5, ror #24
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+        ldr     DAT0, [IN, CHAN0, lsl #2]
 | 
	
		
			
				|  |  | -+        ldr     DAT1, [IN, CHAN1, lsl #2]
 | 
	
		
			
				|  |  | -+        ldr     DAT2, [IN, CHAN2, lsl #2]
 | 
	
		
			
				|  |  | -+        ldr     DAT3, [IN, CHAN3, lsl #2]
 | 
	
		
			
				|  |  | -+   .if IDX1 == 4
 | 
	
		
			
				|  |  | -+        add     IN, IN, #8*4
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+        decr_modulo IDX1, 4, \channels
 | 
	
		
			
				|  |  | -+  .else
 | 
	
		
			
				|  |  | -+   .set SIZE_GROUP1, IDX1
 | 
	
		
			
				|  |  | -+   .if SIZE_GROUP1 > 4
 | 
	
		
			
				|  |  | -+    .set SIZE_GROUP1, 4
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+   .set SIZE_GROUP2, 4 - SIZE_GROUP1
 | 
	
		
			
				|  |  | -+   .if SIZE_GROUP1 == 2
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 0, IN, CHAN, 0 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 1, IN, CHAN, 1 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+        add     IN, IN, #8*4
 | 
	
		
			
				|  |  | -+   .else // SIZE_GROUP1 == 4
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 0, IN, CHAN, 0 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 1, IN, CHAN, 1 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 2, IN, CHAN, 2 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 3, IN, CHAN, 3 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+    .if IDX1 == 4
 | 
	
		
			
				|  |  | -+        add     IN, IN, #8*4
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+        decr_modulo IDX1, SIZE_GROUP1, \channels
 | 
	
		
			
				|  |  | -+   .if SIZE_GROUP2 == 2
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 2, IN, CHAN, 0 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+        loadregoffsh2  DAT, 3, IN, CHAN, 1 + (\channels - IDX1)
 | 
	
		
			
				|  |  | -+    .if IDX1 == 2
 | 
	
		
			
				|  |  | -+        add     IN, IN, #8*4
 | 
	
		
			
				|  |  | -+    .endif
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+        decr_modulo IDX1, SIZE_GROUP2, \channels
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+  .if \channels == 8 // in this case we can corrupt CHAN0-3
 | 
	
		
			
				|  |  | -+        rsb     CHAN0, CHAN0, #8
 | 
	
		
			
				|  |  | -+        rsb     CHAN1, CHAN1, #8
 | 
	
		
			
				|  |  | -+        rsb     CHAN2, CHAN2, #8
 | 
	
		
			
				|  |  | -+        rsb     CHAN3, CHAN3, #8
 | 
	
		
			
				|  |  | -+        lsl     DAT0, #8 + \shift
 | 
	
		
			
				|  |  | -+        lsl     DAT1, #8 + \shift
 | 
	
		
			
				|  |  | -+        lsl     DAT2, #8 + \shift
 | 
	
		
			
				|  |  | -+        lsl     DAT3, #8 + \shift
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT0, lsr CHAN0
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT1, lsr CHAN1
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT2, lsr CHAN2
 | 
	
		
			
				|  |  | -+        eor     CHECK, CHECK, DAT3, lsr CHAN3
 | 
	
		
			
				|  |  | -+  .else
 | 
	
		
			
				|  |  | -+   .if \shift != 0
 | 
	
		
			
				|  |  | -+        lsl     DAT0, #\shift
 | 
	
		
			
				|  |  | -+        lsl     DAT1, #\shift
 | 
	
		
			
				|  |  | -+        lsl     DAT2, #\shift
 | 
	
		
			
				|  |  | -+        lsl     DAT3, #\shift
 | 
	
		
			
				|  |  | -+   .endif
 | 
	
		
			
				|  |  | -+        bic     DAT0, DAT0, #0xff000000
 | 
	
		
			
				|  |  | -+        bic     DAT1, DAT1, #0xff000000
 | 
	
		
			
				|  |  | -+        bic     DAT2, DAT2, #0xff000000
 | 
	
		
			
				|  |  | -+        bic     DAT3, DAT3, #0xff000000
 | 
	
		
			
				|  |  | -+        eorlslreg CHECK, DAT0, CHAN, 0 + (\channels - IDX2)
 | 
	
		
			
				|  |  | -+        eorlslreg CHECK, DAT1, CHAN, 1 + (\channels - IDX2)
 | 
	
		
			
				|  |  | -+   decr_modulo IDX2, 2, \channels
 | 
	
		
			
				|  |  | -+        eorlslreg CHECK, DAT2, CHAN, 0 + (\channels - IDX2)
 | 
	
		
			
				|  |  | -+        eorlslreg CHECK, DAT3, CHAN, 1 + (\channels - IDX2)
 | 
	
		
			
				|  |  | -+   decr_modulo IDX2, 2, \channels
 | 
	
		
			
				|  |  | -+        lsl     DAT0, #8
 | 
	
		
			
				|  |  | -+        lsl     DAT1, #8
 | 
	
		
			
				|  |  | -+        lsl     DAT2, #8
 | 
	
		
			
				|  |  | -+        lsl     DAT3, #8
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+        stm     OUT!, {DAT0 - DAT3}
 | 
	
		
			
				|  |  | -+ .endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+ .set WORDS_PER_LOOP, \channels  // calculate LCM (channels, 4)
 | 
	
		
			
				|  |  | -+ .if (WORDS_PER_LOOP % 2) == 0
 | 
	
		
			
				|  |  | -+  .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .if (WORDS_PER_LOOP % 2) == 0
 | 
	
		
			
				|  |  | -+  .set WORDS_PER_LOOP, WORDS_PER_LOOP / 2
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .set WORDS_PER_LOOP, WORDS_PER_LOOP * 4
 | 
	
		
			
				|  |  | -+ .set SAMPLES_PER_LOOP, WORDS_PER_LOOP / \channels
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+function ff_mlp_pack_output_outoforder_\channels\()ch_\shift\()shift_arm, export=1
 | 
	
		
			
				|  |  | -+ .if SAMPLES_PER_LOOP > 1
 | 
	
		
			
				|  |  | -+        tst     COUNT, #SAMPLES_PER_LOOP - 1  // always seems to be in practice
 | 
	
		
			
				|  |  | -+        bne     X(ff_mlp_pack_output)         // but just in case, branch to C implementation if not
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+        teq     COUNT, #0
 | 
	
		
			
				|  |  | -+        bxeq    lr
 | 
	
		
			
				|  |  | -+        push    {v1-v6,sl,fp,lr}
 | 
	
		
			
				|  |  | -+        ldr     CHAN0, [sp, #(9+2)*4]  // get ch_assign from stack
 | 
	
		
			
				|  |  | -+        ldr     CHAN4, [CHAN0]
 | 
	
		
			
				|  |  | -+ .if \channels == 2
 | 
	
		
			
				|  |  | -+        uxtb    CHAN0, CHAN4, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    CHAN1, CHAN4, ror #8
 | 
	
		
			
				|  |  | -+ .else
 | 
	
		
			
				|  |  | -+        ldr     CHAN5, [CHAN0, #4]
 | 
	
		
			
				|  |  | -+  .if \channels == 6
 | 
	
		
			
				|  |  | -+        uxtb    CHAN0, CHAN4, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    CHAN1, CHAN4, ror #8
 | 
	
		
			
				|  |  | -+        uxtb    CHAN2, CHAN4, ror #16
 | 
	
		
			
				|  |  | -+        uxtb    CHAN3, CHAN4, ror #24
 | 
	
		
			
				|  |  | -+        uxtb    CHAN4, CHAN5, ror #0
 | 
	
		
			
				|  |  | -+        uxtb    CHAN5, CHAN5, ror #8
 | 
	
		
			
				|  |  | -+  .endif
 | 
	
		
			
				|  |  | -+ .endif
 | 
	
		
			
				|  |  | -+ .set IDX1, \channels
 | 
	
		
			
				|  |  | -+ .set IDX2, \channels
 | 
	
		
			
				|  |  | -+0:
 | 
	
		
			
				|  |  | -+ .rept WORDS_PER_LOOP / 4
 | 
	
		
			
				|  |  | -+        output4words
 | 
	
		
			
				|  |  | -+ .endr
 | 
	
		
			
				|  |  | -+        subs    COUNT, COUNT, #SAMPLES_PER_LOOP
 | 
	
		
			
				|  |  | -+        bne     0b
 | 
	
		
			
				|  |  | -+        pop     {v1-v6,sl,fp,pc}
 | 
	
		
			
				|  |  | -+        .ltorg
 | 
	
		
			
				|  |  | -+endfunc
 | 
	
		
			
				|  |  | -+ .purgem output4words
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        .unreq  CHECK
 | 
	
		
			
				|  |  | -+        .unreq  IN
 | 
	
		
			
				|  |  | -+        .unreq  OUT
 | 
	
		
			
				|  |  | -+        .unreq  COUNT
 | 
	
		
			
				|  |  | -+        .unreq  DAT0
 | 
	
		
			
				|  |  | -+        .unreq  DAT1
 | 
	
		
			
				|  |  | -+        .unreq  DAT2
 | 
	
		
			
				|  |  | -+        .unreq  DAT3
 | 
	
		
			
				|  |  | -+        .unreq  CHAN0
 | 
	
		
			
				|  |  | -+        .unreq  CHAN1
 | 
	
		
			
				|  |  | -+        .unreq  CHAN2
 | 
	
		
			
				|  |  | -+        .unreq  CHAN3
 | 
	
		
			
				|  |  | -+        .unreq  CHAN4
 | 
	
		
			
				|  |  | -+        .unreq  CHAN5
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.endif // mixed
 | 
	
		
			
				|  |  | -+.endif // inorder
 | 
	
		
			
				|  |  | -+.endm // implement_pack
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro pack_channels  inorder, channels
 | 
	
		
			
				|  |  | -+        implement_pack  \inorder, \channels, 0
 | 
	
		
			
				|  |  | -+        implement_pack  \inorder, \channels, 1
 | 
	
		
			
				|  |  | -+        implement_pack  \inorder, \channels, 2
 | 
	
		
			
				|  |  | -+        implement_pack  \inorder, \channels, 3
 | 
	
		
			
				|  |  | -+        implement_pack  \inorder, \channels, 4
 | 
	
		
			
				|  |  | -+        implement_pack  \inorder, \channels, 5
 | 
	
		
			
				|  |  | -+        implement_pack  \inorder, \channels, mixed
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+.macro pack_order  inorder
 | 
	
		
			
				|  |  | -+        pack_channels  \inorder, 2
 | 
	
		
			
				|  |  | -+        pack_channels  \inorder, 6
 | 
	
		
			
				|  |  | -+        pack_channels  \inorder, 8
 | 
	
		
			
				|  |  | -+.endm
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        pack_order  0
 | 
	
		
			
				|  |  | -+        pack_order  1
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -index 268dfdd..2d8b98d 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/libavcodec/arm/mlpdsp_init_arm.c
 | 
	
		
			
				|  |  | -@@ -41,8 +41,72 @@ void ff_mlp_rematrix_channel_arm(int32_t *samples,
 | 
	
		
			
				|  |  | -                                  int access_unit_size_pow2,
 | 
	
		
			
				|  |  | -                                  int32_t mask);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#define DECLARE_PACK(order,channels,shift) \
 | 
	
		
			
				|  |  | -+    int32_t ff_mlp_pack_output_##order##order_##channels##ch_##shift##shift_arm(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *);
 | 
	
		
			
				|  |  | -+#define ENUMERATE_PACK(order,channels,shift) \
 | 
	
		
			
				|  |  | -+    ff_mlp_pack_output_##order##order_##channels##ch_##shift##shift_arm,
 | 
	
		
			
				|  |  | -+#define PACK_CHANNELS(macro,order,channels) \
 | 
	
		
			
				|  |  | -+        macro(order,channels,0) \
 | 
	
		
			
				|  |  | -+        macro(order,channels,1) \
 | 
	
		
			
				|  |  | -+        macro(order,channels,2) \
 | 
	
		
			
				|  |  | -+        macro(order,channels,3) \
 | 
	
		
			
				|  |  | -+        macro(order,channels,4) \
 | 
	
		
			
				|  |  | -+        macro(order,channels,5) \
 | 
	
		
			
				|  |  | -+        macro(order,channels,mixed)
 | 
	
		
			
				|  |  | -+#define PACK_ORDER(macro,order) \
 | 
	
		
			
				|  |  | -+        PACK_CHANNELS(macro,order,2) \
 | 
	
		
			
				|  |  | -+        PACK_CHANNELS(macro,order,6) \
 | 
	
		
			
				|  |  | -+        PACK_CHANNELS(macro,order,8)
 | 
	
		
			
				|  |  | -+#define PACK_ALL(macro) \
 | 
	
		
			
				|  |  | -+        PACK_ORDER(macro,outof) \
 | 
	
		
			
				|  |  | -+        PACK_ORDER(macro,in)
 | 
	
		
			
				|  |  | -+PACK_ALL(DECLARE_PACK)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define ff_mlp_pack_output_outoforder_2ch_mixedshift_arm 0
 | 
	
		
			
				|  |  | -+#define ff_mlp_pack_output_outoforder_6ch_mixedshift_arm 0
 | 
	
		
			
				|  |  | -+#define ff_mlp_pack_output_outoforder_8ch_mixedshift_arm 0
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+static int32_t (*mlp_select_pack_output_arm(uint8_t max_matrix_channel,
 | 
	
		
			
				|  |  | -+                                            int is32,
 | 
	
		
			
				|  |  | -+                                            uint8_t *ch_assign,
 | 
	
		
			
				|  |  | -+                                            int8_t *output_shift))(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+    int ch_index;
 | 
	
		
			
				|  |  | -+    int shift = output_shift[0] < 0 || output_shift[0] > 5 ? 6 : output_shift[0];
 | 
	
		
			
				|  |  | -+    int inorder = 1;
 | 
	
		
			
				|  |  | -+    static int32_t (*const routine[2*3*7])(int32_t, int32_t (*)[], void *, uint16_t, uint8_t, int, uint8_t*, int8_t *) = {
 | 
	
		
			
				|  |  | -+            PACK_ALL(ENUMERATE_PACK)
 | 
	
		
			
				|  |  | -+    };
 | 
	
		
			
				|  |  | -+    int i;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (!is32) // don't support 16-bit output (it's not used by TrueHD)
 | 
	
		
			
				|  |  | -+        return ff_mlp_pack_output;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    switch (max_matrix_channel) {
 | 
	
		
			
				|  |  | -+    case 1: ch_index = 0; break;
 | 
	
		
			
				|  |  | -+    case 5: ch_index = 1; break;
 | 
	
		
			
				|  |  | -+    case 7: ch_index = 2; break;
 | 
	
		
			
				|  |  | -+    default: return ff_mlp_pack_output;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    for (i = 0; i <= max_matrix_channel; i++) {
 | 
	
		
			
				|  |  | -+        if (shift != 6 && output_shift[i] != shift)
 | 
	
		
			
				|  |  | -+            shift = 6; // indicate mixed shifts
 | 
	
		
			
				|  |  | -+        if (ch_assign[i] != i)
 | 
	
		
			
				|  |  | -+            inorder = 0;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    if (shift == 6 && !inorder)
 | 
	
		
			
				|  |  | -+        return ff_mlp_pack_output; // can't currently handle both an order array and a shift array
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    return routine[(inorder*3+ch_index)*7+shift];
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - av_cold void ff_mlpdsp_init_arm(MLPDSPContext *c)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+    int cpu_flags = av_get_cpu_flags();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     c->mlp_filter_channel = ff_mlp_filter_channel_arm;
 | 
	
		
			
				|  |  | -     c->mlp_rematrix_channel = ff_mlp_rematrix_channel_arm;
 | 
	
		
			
				|  |  | -+    if (cpu_flags & AV_CPU_FLAG_ARMV6)
 | 
	
		
			
				|  |  | -+        c->mlp_select_pack_output = mlp_select_pack_output_arm;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 9af15bf0b7bc7940bd8bcc9ddae23178c9723bd6 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Thu, 14 Nov 2013 19:48:41 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 14/94] More efficient infobool expression evaluator
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Expession infobools are evaluated at runtime from one or more single infobools
 | 
	
		
			
				|  |  | -and a combination of boolean NOT, AND and OR operators. Previously, parsing
 | 
	
		
			
				|  |  | -produced a vector of operands (leaf nodes) and operators in postfix
 | 
	
		
			
				|  |  | -(reverse-Polish) form, and evaluated all leaf nodes every time the expression
 | 
	
		
			
				|  |  | -was evaluated. But this ignores the fact that in many cases, once one operand
 | 
	
		
			
				|  |  | -of an AND or OR operation has been evaluated, there is no need to evaluate the
 | 
	
		
			
				|  |  | -other operand because its value can have no effect on the ultimate result. It
 | 
	
		
			
				|  |  | -is also worth noting that AND and OR operations are associative, meaning they
 | 
	
		
			
				|  |  | -can be rearranged at runtime to better suit the selected skin.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This patch rewrites the expression parsing and evaluation code. Now the
 | 
	
		
			
				|  |  | -internal repreentation is in the form of a tree where leaf nodes represent a
 | 
	
		
			
				|  |  | -single infobool, and branch nodes represent either an AND or an OR operation
 | 
	
		
			
				|  |  | -on two or more child nodes.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Expressions are rewritten at parse time into a form which favours the
 | 
	
		
			
				|  |  | -formation of groups of associative nodes. These groups are then reordered at
 | 
	
		
			
				|  |  | -evaluation time such that nodes whose value renders the evaluation of the
 | 
	
		
			
				|  |  | -remainder of the group unnecessary tend to be evaluated first (these are
 | 
	
		
			
				|  |  | -true nodes for OR subexpressions, or false nodes for AND subexpressions).
 | 
	
		
			
				|  |  | -The end effect is to minimise the number of leaf nodes that need to be
 | 
	
		
			
				|  |  | -evaluated in order to determine the value of the expression. The runtime
 | 
	
		
			
				|  |  | -adaptability has the advantage of not being customised for any particular skin.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The modifications to the expression at parse time fall into two groups:
 | 
	
		
			
				|  |  | -1) Moving logical NOTs so that they are only applied to leaf nodes.
 | 
	
		
			
				|  |  | -   For example, rewriting ![A+B]|C as !A|!B|C allows reordering such that
 | 
	
		
			
				|  |  | -   any of the three leaves can be evaluated first.
 | 
	
		
			
				|  |  | -2) Combining adjacent AND or OR operations such that each path from the root
 | 
	
		
			
				|  |  | -   to a leaf encounters a strictly alternating pattern of AND and OR
 | 
	
		
			
				|  |  | -   operations. So [A|B]|[C|D+[[E|F]|G] becomes A|B|C|[D+[E|F|G]].
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -I measured the effect while the Videos window of the default skin was open
 | 
	
		
			
				|  |  | -(but idle) on a Raspberry Pi, and this reduced the CPU usage by 2.8% from
 | 
	
		
			
				|  |  | -41.9% to 39.1%:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Before          After
 | 
	
		
			
				|  |  | -          Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -IdleCPU%  41.9   0.5      39.1   0.9     100.0%      +7.0%
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/interfaces/info/InfoExpression.cpp | 313 +++++++++++++++++++++-----------
 | 
	
		
			
				|  |  | - xbmc/interfaces/info/InfoExpression.h   |  63 ++++++-
 | 
	
		
			
				|  |  | - 2 files changed, 269 insertions(+), 107 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/interfaces/info/InfoExpression.cpp b/xbmc/interfaces/info/InfoExpression.cpp
 | 
	
		
			
				|  |  | -index f4d32c1..db461dd 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/interfaces/info/InfoExpression.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/interfaces/info/InfoExpression.cpp
 | 
	
		
			
				|  |  | -@@ -22,6 +22,9 @@
 | 
	
		
			
				|  |  | - #include <stack>
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - #include "GUIInfoManager.h"
 | 
	
		
			
				|  |  | -+#include <list>
 | 
	
		
			
				|  |  | -+#include <boost/shared_ptr.hpp>
 | 
	
		
			
				|  |  | -+#include <boost/make_shared.hpp>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - using namespace std;
 | 
	
		
			
				|  |  | - using namespace INFO;
 | 
	
		
			
				|  |  | -@@ -40,21 +43,89 @@ void InfoSingle::Update(const CGUIListItem *item)
 | 
	
		
			
				|  |  | - InfoExpression::InfoExpression(const std::string &expression, int context)
 | 
	
		
			
				|  |  | - : InfoBool(expression, context)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  Parse(expression);
 | 
	
		
			
				|  |  | -+  if (!Parse(expression))
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "Error parsing boolean expression %s", expression.c_str());
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void InfoExpression::Update(const CGUIListItem *item)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  Evaluate(item, m_value);
 | 
	
		
			
				|  |  | -+  m_value = m_expression_tree->Evaluate(item);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --#define OPERATOR_LB   5
 | 
	
		
			
				|  |  | --#define OPERATOR_RB   4
 | 
	
		
			
				|  |  | --#define OPERATOR_NOT  3
 | 
	
		
			
				|  |  | --#define OPERATOR_AND  2
 | 
	
		
			
				|  |  | --#define OPERATOR_OR   1
 | 
	
		
			
				|  |  | -+/* Expressions are rewritten at parse time into a form which favours the
 | 
	
		
			
				|  |  | -+ * formation of groups of associative nodes. These groups are then reordered at
 | 
	
		
			
				|  |  | -+ * evaluation time such that nodes whose value renders the evaluation of the
 | 
	
		
			
				|  |  | -+ * remainder of the group unnecessary tend to be evaluated first (these are
 | 
	
		
			
				|  |  | -+ * true nodes for OR subexpressions, or false nodes for AND subexpressions).
 | 
	
		
			
				|  |  | -+ * The end effect is to minimise the number of leaf nodes that need to be
 | 
	
		
			
				|  |  | -+ * evaluated in order to determine the value of the expression. The runtime
 | 
	
		
			
				|  |  | -+ * adaptability has the advantage of not being customised for any particular skin.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ * The modifications to the expression at parse time fall into two groups:
 | 
	
		
			
				|  |  | -+ * 1) Moving logical NOTs so that they are only applied to leaf nodes.
 | 
	
		
			
				|  |  | -+ *    For example, rewriting ![A+B]|C as !A|!B|C allows reordering such that
 | 
	
		
			
				|  |  | -+ *    any of the three leaves can be evaluated first.
 | 
	
		
			
				|  |  | -+ * 2) Combining adjacent AND or OR operations such that each path from the root
 | 
	
		
			
				|  |  | -+ *    to a leaf encounters a strictly alternating pattern of AND and OR
 | 
	
		
			
				|  |  | -+ *    operations. So [A|B]|[C|D+[[E|F]|G] becomes A|B|C|[D+[E|F|G]].
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+bool InfoExpression::InfoLeaf::Evaluate(const CGUIListItem *item)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return m_invert ^ m_info->Get(item);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --short InfoExpression::GetOperator(const char ch) const
 | 
	
		
			
				|  |  | -+InfoExpression::InfoAssociativeGroup::InfoAssociativeGroup(
 | 
	
		
			
				|  |  | -+    bool and_not_or,
 | 
	
		
			
				|  |  | -+    const InfoSubexpressionPtr &left,
 | 
	
		
			
				|  |  | -+    const InfoSubexpressionPtr &right)
 | 
	
		
			
				|  |  | -+    : m_and_not_or(and_not_or)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  AddChild(right);
 | 
	
		
			
				|  |  | -+  AddChild(left);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void InfoExpression::InfoAssociativeGroup::AddChild(const InfoSubexpressionPtr &child)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  m_children.push_front(child); // largely undoes the effect of parsing right-associative
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void InfoExpression::InfoAssociativeGroup::Merge(InfoAssociativeGroup *other)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  m_children.splice(m_children.end(), other->m_children);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+bool InfoExpression::InfoAssociativeGroup::Evaluate(const CGUIListItem *item)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  /* Handle either AND or OR by using the relation
 | 
	
		
			
				|  |  | -+   * A AND B == !(!A OR !B)
 | 
	
		
			
				|  |  | -+   * to convert ANDs into ORs
 | 
	
		
			
				|  |  | -+   */
 | 
	
		
			
				|  |  | -+  std::list<InfoSubexpressionPtr>::iterator last = m_children.end();
 | 
	
		
			
				|  |  | -+  std::list<InfoSubexpressionPtr>::iterator it = m_children.begin();
 | 
	
		
			
				|  |  | -+  bool result = m_and_not_or ^ (*it)->Evaluate(item);
 | 
	
		
			
				|  |  | -+  while (!result && ++it != last)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    result = m_and_not_or ^ (*it)->Evaluate(item);
 | 
	
		
			
				|  |  | -+    if (result)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      /* Move this child to the head of the list so we evaluate faster next time */
 | 
	
		
			
				|  |  | -+      InfoSubexpressionPtr p = *it;
 | 
	
		
			
				|  |  | -+      m_children.erase(it);
 | 
	
		
			
				|  |  | -+      m_children.push_front(p);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  return m_and_not_or ^ result;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/* Expressions are parsed using the shunting-yard algorithm. Binary operators
 | 
	
		
			
				|  |  | -+ * (AND/OR) are treated as right-associative so that we don't need to make a
 | 
	
		
			
				|  |  | -+ * special case for the unary NOT operator. This has no effect upon the answers
 | 
	
		
			
				|  |  | -+ * generated, though the initial sequence of evaluation of leaves may be
 | 
	
		
			
				|  |  | -+ * different from what you might expect.
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+InfoExpression::operator_t InfoExpression::GetOperator(char ch)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (ch == '[')
 | 
	
		
			
				|  |  | -     return OPERATOR_LB;
 | 
	
		
			
				|  |  | -@@ -67,122 +138,160 @@ short InfoExpression::GetOperator(const char ch) const
 | 
	
		
			
				|  |  | -   else if (ch == '|')
 | 
	
		
			
				|  |  | -     return OPERATOR_OR;
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | --    return 0;
 | 
	
		
			
				|  |  | -+    return OPERATOR_NONE;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void InfoExpression::Parse(const std::string &expression)
 | 
	
		
			
				|  |  | -+void InfoExpression::OperatorPop(std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  stack<char> operators;
 | 
	
		
			
				|  |  | --  std::string operand;
 | 
	
		
			
				|  |  | --  for (unsigned int i = 0; i < expression.size(); i++)
 | 
	
		
			
				|  |  | -+  operator_t op2 = operator_stack.top();
 | 
	
		
			
				|  |  | -+  operator_stack.pop();
 | 
	
		
			
				|  |  | -+  if (op2 == OPERATOR_NOT)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if (GetOperator(expression[i]))
 | 
	
		
			
				|  |  | -+    invert = !invert;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    // At this point, it can only be OPERATOR_AND or OPERATOR_OR
 | 
	
		
			
				|  |  | -+    if (invert)
 | 
	
		
			
				|  |  | -+      op2 = (operator_t) (OPERATOR_AND ^ OPERATOR_OR ^ op2);
 | 
	
		
			
				|  |  | -+    node_type_t new_type = op2 == OPERATOR_AND ? NODE_AND : NODE_OR;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    InfoSubexpressionPtr right = nodes.top();
 | 
	
		
			
				|  |  | -+    nodes.pop();
 | 
	
		
			
				|  |  | -+    InfoSubexpressionPtr left = nodes.top();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    node_type_t right_type = node_types.top();
 | 
	
		
			
				|  |  | -+    node_types.pop();
 | 
	
		
			
				|  |  | -+    node_type_t left_type = node_types.top();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    // Combine associative operations into the same node where possible
 | 
	
		
			
				|  |  | -+    if (left_type == new_type && right_type == new_type)
 | 
	
		
			
				|  |  | -+      (static_cast<InfoAssociativeGroup *>(left.get()))->Merge(static_cast<InfoAssociativeGroup *>(right.get()));
 | 
	
		
			
				|  |  | -+    else if (left_type == new_type)
 | 
	
		
			
				|  |  | -+      (static_cast<InfoAssociativeGroup *>(left.get()))->AddChild(right);
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      // cleanup any operand, translate and put into our expression list
 | 
	
		
			
				|  |  | --      if (!operand.empty())
 | 
	
		
			
				|  |  | -+      nodes.pop();
 | 
	
		
			
				|  |  | -+      node_types.pop();
 | 
	
		
			
				|  |  | -+      if (right_type == new_type)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        InfoPtr info = g_infoManager.Register(operand, m_context);
 | 
	
		
			
				|  |  | --        if (info)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          m_listItemDependent |= info->ListItemDependent();
 | 
	
		
			
				|  |  | --          m_postfix.push_back(m_operands.size());
 | 
	
		
			
				|  |  | --          m_operands.push_back(info);
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --        operand.clear();
 | 
	
		
			
				|  |  | -+        (static_cast<InfoAssociativeGroup *>(right.get()))->AddChild(left);
 | 
	
		
			
				|  |  | -+        nodes.push(right);
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --      // handle closing parenthesis
 | 
	
		
			
				|  |  | --      if (expression[i] == ']')
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        while (!operators.empty())
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          char oper = operators.top();
 | 
	
		
			
				|  |  | --          operators.pop();
 | 
	
		
			
				|  |  | -+      else
 | 
	
		
			
				|  |  | -+        nodes.push(boost::make_shared<InfoAssociativeGroup>(new_type == NODE_AND, left, right));
 | 
	
		
			
				|  |  | -+      node_types.push(new_type);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void InfoExpression::ProcessOperator(operator_t op, std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  // Handle any higher-priority stacked operators, except when the new operator is left-bracket.
 | 
	
		
			
				|  |  | -+  // For a right-bracket, this will stop with the matching left-bracket at the top of the operator stack.
 | 
	
		
			
				|  |  | -+  if (op != OPERATOR_LB)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    while (operator_stack.size() > 0 && operator_stack.top() > op)
 | 
	
		
			
				|  |  | -+      OperatorPop(operator_stack, invert, node_types, nodes);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  if (op == OPERATOR_RB)
 | 
	
		
			
				|  |  | -+    operator_stack.pop(); // remove the matching left-bracket
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    operator_stack.push(op);
 | 
	
		
			
				|  |  | -+  if (op == OPERATOR_NOT)
 | 
	
		
			
				|  |  | -+    invert = !invert;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --          if (oper == '[')
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | -+bool InfoExpression::ProcessOperand(std::string &operand, bool invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  InfoPtr info = g_infoManager.Register(operand, m_context);
 | 
	
		
			
				|  |  | -+  if (!info)
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  m_listItemDependent |= info->ListItemDependent();
 | 
	
		
			
				|  |  | -+  nodes.push(boost::make_shared<InfoLeaf>(info, invert));
 | 
	
		
			
				|  |  | -+  node_types.push(NODE_LEAF);
 | 
	
		
			
				|  |  | -+  operand.clear();
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --          m_postfix.push_back(-GetOperator(oper)); // negative denotes operator
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | -+bool InfoExpression::Parse(const std::string &expression)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  const char *s = expression.c_str();
 | 
	
		
			
				|  |  | -+  std::string operand;
 | 
	
		
			
				|  |  | -+  std::stack<operator_t> operator_stack;
 | 
	
		
			
				|  |  | -+  bool invert = false;
 | 
	
		
			
				|  |  | -+  std::stack<node_type_t> node_types;
 | 
	
		
			
				|  |  | -+  std::stack<InfoSubexpressionPtr> nodes;
 | 
	
		
			
				|  |  | -+  // The next two are for syntax-checking purposes
 | 
	
		
			
				|  |  | -+  bool after_binaryoperator = true;
 | 
	
		
			
				|  |  | -+  int bracket_count = 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  char c;
 | 
	
		
			
				|  |  | -+  // Skip leading whitespace - don't want it to count as an operand if that's all there is
 | 
	
		
			
				|  |  | -+  do
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    c = *s++;
 | 
	
		
			
				|  |  | -+  } while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
 | 
	
		
			
				|  |  | -+  s--;
 | 
	
		
			
				|  |  | -+  while ((c = *s++) != '\0')
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    operator_t op;
 | 
	
		
			
				|  |  | -+    if ((op = GetOperator(c)) != OPERATOR_NONE)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      // Character is an operator
 | 
	
		
			
				|  |  | -+      if ((!after_binaryoperator && (c == '!' || c == '[')) ||
 | 
	
		
			
				|  |  | -+          (after_binaryoperator && (c == ']' || c == '+' || c == '|')))
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "Misplaced %c", c);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --      else
 | 
	
		
			
				|  |  | -+      if (c == '[')
 | 
	
		
			
				|  |  | -+        bracket_count++;
 | 
	
		
			
				|  |  | -+      else if (c == ']' && bracket_count-- == 0)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "Unmatched ]");
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      if (operand.size() > 0 && !ProcessOperand(operand, invert, node_types, nodes))
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        // all other operators we pop off the stack any operator
 | 
	
		
			
				|  |  | --        // that has a higher priority than the one we have.
 | 
	
		
			
				|  |  | --        while (!operators.empty() && GetOperator(operators.top()) > GetOperator(expression[i]))
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          // only handle parenthesis once they're closed.
 | 
	
		
			
				|  |  | --          if (operators.top() == '[' && expression[i] != ']')
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --          m_postfix.push_back(-GetOperator(operators.top()));  // negative denotes operator
 | 
	
		
			
				|  |  | --          operators.pop();
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --        operators.push(expression[i]);
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "Bad operand '%s'", operand.c_str());
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -+      ProcessOperator(op, operator_stack, invert, node_types, nodes);
 | 
	
		
			
				|  |  | -+      if (c == '+' || c == '|')
 | 
	
		
			
				|  |  | -+        after_binaryoperator = true;
 | 
	
		
			
				|  |  | -+      // Skip trailing whitespace - don't want it to count as an operand if that's all there is
 | 
	
		
			
				|  |  | -+      do
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        c = *s++;
 | 
	
		
			
				|  |  | -+      } while (c == ' ' || c == '\t' || c == '\r' || c == '\n');
 | 
	
		
			
				|  |  | -+      s--;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     else
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      operand += expression[i];
 | 
	
		
			
				|  |  | -+      // Character is part of operand
 | 
	
		
			
				|  |  | -+      operand += c;
 | 
	
		
			
				|  |  | -+      after_binaryoperator = false;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (!operand.empty())
 | 
	
		
			
				|  |  | -+  if (bracket_count > 0)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    InfoPtr info = g_infoManager.Register(operand, m_context);
 | 
	
		
			
				|  |  | --    if (info)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      m_listItemDependent |= info->ListItemDependent();
 | 
	
		
			
				|  |  | --      m_postfix.push_back(m_operands.size());
 | 
	
		
			
				|  |  | --      m_operands.push_back(info);
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "Unmatched [");
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // finish up by adding any operators
 | 
	
		
			
				|  |  | --  while (!operators.empty())
 | 
	
		
			
				|  |  | -+  if (after_binaryoperator)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    m_postfix.push_back(-GetOperator(operators.top()));  // negative denotes operator
 | 
	
		
			
				|  |  | --    operators.pop();
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "Missing operand");
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // test evaluate
 | 
	
		
			
				|  |  | --  bool test;
 | 
	
		
			
				|  |  | --  if (!Evaluate(NULL, test))
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "Error evaluating boolean expression %s", expression.c_str());
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --bool InfoExpression::Evaluate(const CGUIListItem *item, bool &result)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  stack<bool> save;
 | 
	
		
			
				|  |  | --  for (vector<short>::const_iterator it = m_postfix.begin(); it != m_postfix.end(); ++it)
 | 
	
		
			
				|  |  | -+  if (operand.size() > 0 && !ProcessOperand(operand, invert, node_types, nodes))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    short expr = *it;
 | 
	
		
			
				|  |  | --    if (expr == -OPERATOR_NOT)
 | 
	
		
			
				|  |  | --    { // NOT the top item on the stack
 | 
	
		
			
				|  |  | --      if (save.empty()) return false;
 | 
	
		
			
				|  |  | --      bool expr = save.top();
 | 
	
		
			
				|  |  | --      save.pop();
 | 
	
		
			
				|  |  | --      save.push(!expr);
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else if (expr == -OPERATOR_AND)
 | 
	
		
			
				|  |  | --    { // AND the top two items on the stack
 | 
	
		
			
				|  |  | --      if (save.size() < 2) return false;
 | 
	
		
			
				|  |  | --      bool right = save.top(); save.pop();
 | 
	
		
			
				|  |  | --      bool left = save.top(); save.pop();
 | 
	
		
			
				|  |  | --      save.push(left && right);
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else if (expr == -OPERATOR_OR)
 | 
	
		
			
				|  |  | --    { // OR the top two items on the stack
 | 
	
		
			
				|  |  | --      if (save.size() < 2) return false;
 | 
	
		
			
				|  |  | --      bool right = save.top(); save.pop();
 | 
	
		
			
				|  |  | --      bool left = save.top(); save.pop();
 | 
	
		
			
				|  |  | --      save.push(left || right);
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else if (expr >= 0) // operand
 | 
	
		
			
				|  |  | --      save.push(m_operands[expr]->Get(item));
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  if (save.size() != 1)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "Bad operand '%s'", operand.c_str());
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | --  result = save.top();
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  while (operator_stack.size() > 0)
 | 
	
		
			
				|  |  | -+    OperatorPop(operator_stack, invert, node_types, nodes);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_expression_tree = nodes.top();
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -diff --git a/xbmc/interfaces/info/InfoExpression.h b/xbmc/interfaces/info/InfoExpression.h
 | 
	
		
			
				|  |  | -index 4e0faee..0a91399 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/interfaces/info/InfoExpression.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/interfaces/info/InfoExpression.h
 | 
	
		
			
				|  |  | -@@ -21,6 +21,8 @@
 | 
	
		
			
				|  |  | - #pragma once
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include <vector>
 | 
	
		
			
				|  |  | -+#include <list>
 | 
	
		
			
				|  |  | -+#include <stack>
 | 
	
		
			
				|  |  | - #include "InfoBool.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - class CGUIListItem;
 | 
	
		
			
				|  |  | -@@ -50,12 +52,63 @@ class InfoExpression : public InfoBool
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   virtual void Update(const CGUIListItem *item);
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | --  void Parse(const std::string &expression);
 | 
	
		
			
				|  |  | --  bool Evaluate(const CGUIListItem *item, bool &result);
 | 
	
		
			
				|  |  | --  short GetOperator(const char ch) const;
 | 
	
		
			
				|  |  | -+  typedef enum
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    OPERATOR_NONE  = 0,
 | 
	
		
			
				|  |  | -+    OPERATOR_LB,  // 1
 | 
	
		
			
				|  |  | -+    OPERATOR_RB,  // 2
 | 
	
		
			
				|  |  | -+    OPERATOR_OR,  // 3
 | 
	
		
			
				|  |  | -+    OPERATOR_AND, // 4
 | 
	
		
			
				|  |  | -+    OPERATOR_NOT, // 5
 | 
	
		
			
				|  |  | -+  } operator_t;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  std::vector<short> m_postfix;         ///< the postfix form of the expression (operators and operand indicies)
 | 
	
		
			
				|  |  | --  std::vector<InfoPtr> m_operands;      ///< the operands in the expression
 | 
	
		
			
				|  |  | -+  typedef enum
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    NODE_LEAF,
 | 
	
		
			
				|  |  | -+    NODE_AND,
 | 
	
		
			
				|  |  | -+    NODE_OR,
 | 
	
		
			
				|  |  | -+  } node_type_t;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // An abstract base class for nodes in the expression tree
 | 
	
		
			
				|  |  | -+  class InfoSubexpression
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+  public:
 | 
	
		
			
				|  |  | -+    virtual ~InfoSubexpression(void) {}; // so we can destruct derived classes using a pointer to their base class
 | 
	
		
			
				|  |  | -+    virtual bool Evaluate(const CGUIListItem *item) = 0;
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  typedef boost::shared_ptr<InfoSubexpression> InfoSubexpressionPtr;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // A leaf node in the expression tree
 | 
	
		
			
				|  |  | -+  class InfoLeaf : public InfoSubexpression
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+  public:
 | 
	
		
			
				|  |  | -+    InfoLeaf(InfoPtr info, bool invert) : m_info(info), m_invert(invert) {};
 | 
	
		
			
				|  |  | -+    virtual bool Evaluate(const CGUIListItem *item);
 | 
	
		
			
				|  |  | -+  private:
 | 
	
		
			
				|  |  | -+    InfoPtr m_info;
 | 
	
		
			
				|  |  | -+    bool m_invert;
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // A branch node in the expression tree
 | 
	
		
			
				|  |  | -+  class InfoAssociativeGroup : public InfoSubexpression
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+  public:
 | 
	
		
			
				|  |  | -+    InfoAssociativeGroup(bool and_not_or, const InfoSubexpressionPtr &left, const InfoSubexpressionPtr &right);
 | 
	
		
			
				|  |  | -+    void AddChild(const InfoSubexpressionPtr &child);
 | 
	
		
			
				|  |  | -+    void Merge(InfoAssociativeGroup *other);
 | 
	
		
			
				|  |  | -+    virtual bool Evaluate(const CGUIListItem *item);
 | 
	
		
			
				|  |  | -+  private:
 | 
	
		
			
				|  |  | -+    bool m_and_not_or;
 | 
	
		
			
				|  |  | -+    std::list<InfoSubexpressionPtr> m_children;
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  static operator_t GetOperator(char ch);
 | 
	
		
			
				|  |  | -+  static void OperatorPop(std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes);
 | 
	
		
			
				|  |  | -+  static void ProcessOperator(operator_t op, std::stack<operator_t> &operator_stack, bool &invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes);
 | 
	
		
			
				|  |  | -+  bool ProcessOperand(std::string &operand, bool invert, std::stack<node_type_t> &node_types, std::stack<InfoSubexpressionPtr> &nodes);
 | 
	
		
			
				|  |  | -+  bool Parse(const std::string &expression);
 | 
	
		
			
				|  |  | -+  InfoSubexpressionPtr m_expression_tree;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 36067cf823d539a00eea75d561ac78a4b1431a66 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Mon, 24 Mar 2014 22:26:21 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 15/94] Where an infobool expression failed to parse, evaluate
 | 
	
		
			
				|  |  | - the infobool as false. Previously, this would result in a segfault due to the
 | 
	
		
			
				|  |  | - dereferencing of an uninitialised pointer to the head of the expression tree.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/interfaces/info/InfoExpression.cpp | 3 +++
 | 
	
		
			
				|  |  | - 1 file changed, 3 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/interfaces/info/InfoExpression.cpp b/xbmc/interfaces/info/InfoExpression.cpp
 | 
	
		
			
				|  |  | -index db461dd..7c54064 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/interfaces/info/InfoExpression.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/interfaces/info/InfoExpression.cpp
 | 
	
		
			
				|  |  | -@@ -44,7 +44,10 @@ InfoExpression::InfoExpression(const std::string &expression, int context)
 | 
	
		
			
				|  |  | - : InfoBool(expression, context)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (!Parse(expression))
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "Error parsing boolean expression %s", expression.c_str());
 | 
	
		
			
				|  |  | -+    m_expression_tree = boost::make_shared<InfoLeaf>(g_infoManager.Register("false", 0), false);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void InfoExpression::Update(const CGUIListItem *item)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7f2870606f1e183d70b1dc2dbc07fa8bc437d0cc Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Tue, 26 Nov 2013 20:09:48 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 16/94] Add caching of infolabels
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The functions CGUIInfoLabel::GetLabel and CGUIInfoLabel::GetItemLabel take
 | 
	
		
			
				|  |  | -a number of strings returned from CGUIInfoManager::GetImage or
 | 
	
		
			
				|  |  | -CGUIInfoManager::GetLabel, and combine them with various constant strings
 | 
	
		
			
				|  |  | -which were determined during CGUIInfoLabel::Parse.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Rather than perform all the string operations on every call, this patch
 | 
	
		
			
				|  |  | -changes to use a two-pass process: first it queries all the GetImage/GetLabel
 | 
	
		
			
				|  |  | -strings, and then only if at least one of them has changed does it bother
 | 
	
		
			
				|  |  | -rebuilding the resultant string - otherwise it re-uses the copy built on a
 | 
	
		
			
				|  |  | -preceding call.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -CGUIInfoLabel::GetLabel/GetItemLabel are also changed to return string
 | 
	
		
			
				|  |  | -references, rather than forcing an additional string copy.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -I have measured the effect while the Videos window of the default skin was
 | 
	
		
			
				|  |  | -open (but idle) on a Raspberry Pi, and this reduced the CPU usage by 0.8%
 | 
	
		
			
				|  |  | -from 36.2% to 35.4%:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -          Before          After
 | 
	
		
			
				|  |  | -          Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -IdleCPU%  36.2   0.5      35.4   0.5     99.9%       +2.2%
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIInfoTypes.cpp | 102 +++++++++++++++++++++++++++++++++----------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIInfoTypes.h   |  11 ++++-
 | 
	
		
			
				|  |  | - 2 files changed, 87 insertions(+), 26 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIInfoTypes.cpp b/xbmc/guilib/GUIInfoTypes.cpp
 | 
	
		
			
				|  |  | -index 6977e0f..d78c26a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIInfoTypes.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIInfoTypes.cpp
 | 
	
		
			
				|  |  | -@@ -136,37 +136,64 @@ void CGUIInfoLabel::SetLabel(const CStdString &label, const CStdString &fallback
 | 
	
		
			
				|  |  | -   Parse(label, context);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --CStdString CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, CStdString *fallback /*= NULL*/) const
 | 
	
		
			
				|  |  | -+const std::string &CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage, CStdString *fallback /*= NULL*/) const
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  CStdString label;
 | 
	
		
			
				|  |  | --  for (unsigned int i = 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -+  for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     const CInfoPortion &portion = m_info[i];
 | 
	
		
			
				|  |  | -     if (portion.m_info)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      CStdString infoLabel;
 | 
	
		
			
				|  |  | -+      std::string infoLabel;
 | 
	
		
			
				|  |  | -       if (preferImage)
 | 
	
		
			
				|  |  | -         infoLabel = g_infoManager.GetImage(portion.m_info, contextWindow, fallback);
 | 
	
		
			
				|  |  | -       if (infoLabel.empty())
 | 
	
		
			
				|  |  | -         infoLabel = g_infoManager.GetLabel(portion.m_info, contextWindow, fallback);
 | 
	
		
			
				|  |  | --      if (!infoLabel.empty())
 | 
	
		
			
				|  |  | --        label += portion.GetLabel(infoLabel);
 | 
	
		
			
				|  |  | -+      if (j == m_labelPortions.size())
 | 
	
		
			
				|  |  | -+        m_labelPortions.push_back(infoLabel);
 | 
	
		
			
				|  |  | -+      else if (infoLabel != m_labelPortions[j])
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        m_labelPortions[j] = infoLabel;
 | 
	
		
			
				|  |  | -+        m_labelDirty = true;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      j++;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    { // no info, so just append the prefix
 | 
	
		
			
				|  |  | --      label += portion.m_prefix;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  if (m_labelDirty)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_label.clear();
 | 
	
		
			
				|  |  | -+    for (unsigned int i = 0, j= 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      const CInfoPortion &portion = m_info[i];
 | 
	
		
			
				|  |  | -+      if (portion.m_info)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        if (!m_labelPortions[j].empty())
 | 
	
		
			
				|  |  | -+          m_label += portion.GetLabel(m_labelPortions[j]);
 | 
	
		
			
				|  |  | -+        j++;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      else
 | 
	
		
			
				|  |  | -+      { // no info, so just append the prefix
 | 
	
		
			
				|  |  | -+        m_label += portion.m_prefix;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+    if (m_label.empty())  // empty label, use the fallback
 | 
	
		
			
				|  |  | -+      m_label = m_fallback;
 | 
	
		
			
				|  |  | -+    m_labelDirty = false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  if (label.empty())  // empty label, use the fallback
 | 
	
		
			
				|  |  | --    return m_fallback;
 | 
	
		
			
				|  |  | --  return label;
 | 
	
		
			
				|  |  | -+  return m_label;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, CStdString *fallback /*= NULL*/) const
 | 
	
		
			
				|  |  | -+const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImages, CStdString *fallback /*= NULL*/) const
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if (!item->IsFileItem()) return "";
 | 
	
		
			
				|  |  | --  CStdString label;
 | 
	
		
			
				|  |  | --  for (unsigned int i = 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -+  if (!item->IsFileItem())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (m_itemLabelDirty)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      m_itemLabel = "";
 | 
	
		
			
				|  |  | -+      m_itemLabelDirty = false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    return m_itemLabel;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     const CInfoPortion &portion = m_info[i];
 | 
	
		
			
				|  |  | -     if (portion.m_info)
 | 
	
		
			
				|  |  | -@@ -176,17 +203,38 @@ CStdString CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool preferImag
 | 
	
		
			
				|  |  | -         infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info, fallback);
 | 
	
		
			
				|  |  | -       else
 | 
	
		
			
				|  |  | -         infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info, fallback);
 | 
	
		
			
				|  |  | --      if (!infoLabel.empty())
 | 
	
		
			
				|  |  | --        label += portion.GetLabel(infoLabel);
 | 
	
		
			
				|  |  | -+      if (j == m_itemLabelPortions.size())
 | 
	
		
			
				|  |  | -+        m_itemLabelPortions.push_back(infoLabel);
 | 
	
		
			
				|  |  | -+      else if (infoLabel != m_itemLabelPortions[j])
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        m_itemLabelPortions[j] = infoLabel;
 | 
	
		
			
				|  |  | -+        m_itemLabelDirty = true;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      j++;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    { // no info, so just append the prefix
 | 
	
		
			
				|  |  | --      label += portion.m_prefix;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  if (m_itemLabelDirty)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_itemLabel.clear();
 | 
	
		
			
				|  |  | -+    for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      const CInfoPortion &portion = m_info[i];
 | 
	
		
			
				|  |  | -+      if (portion.m_info)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        if (!m_itemLabelPortions[j].empty())
 | 
	
		
			
				|  |  | -+          m_itemLabel += portion.GetLabel(m_itemLabelPortions[j]);
 | 
	
		
			
				|  |  | -+        j++;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      else
 | 
	
		
			
				|  |  | -+      { // no info, so just append the prefix
 | 
	
		
			
				|  |  | -+        m_itemLabel += portion.m_prefix;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+    if (m_itemLabel.empty())
 | 
	
		
			
				|  |  | -+      m_itemLabel = m_fallback;
 | 
	
		
			
				|  |  | -+    m_itemLabelDirty = false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  if (label.empty())
 | 
	
		
			
				|  |  | --    return m_fallback;
 | 
	
		
			
				|  |  | --  return label;
 | 
	
		
			
				|  |  | -+  return m_itemLabel;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool CGUIInfoLabel::IsEmpty() const
 | 
	
		
			
				|  |  | -@@ -277,6 +325,12 @@ const static infoformat infoformatmap[] = {{ "$INFO[",    FORMATINFO },
 | 
	
		
			
				|  |  | - void CGUIInfoLabel::Parse(const CStdString &label, int context)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_info.clear();
 | 
	
		
			
				|  |  | -+  m_labelDirty = true;
 | 
	
		
			
				|  |  | -+  m_label.clear();
 | 
	
		
			
				|  |  | -+  m_labelPortions.clear();
 | 
	
		
			
				|  |  | -+  m_itemLabelDirty = true;
 | 
	
		
			
				|  |  | -+  m_itemLabel.clear();
 | 
	
		
			
				|  |  | -+  m_itemLabelPortions.clear();
 | 
	
		
			
				|  |  | -   // Step 1: Replace all $LOCALIZE[number] with the real string
 | 
	
		
			
				|  |  | -   CStdString work = ReplaceLocalize(label);
 | 
	
		
			
				|  |  | -   // Step 2: Replace all $ADDON[id number] with the real string
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIInfoTypes.h b/xbmc/guilib/GUIInfoTypes.h
 | 
	
		
			
				|  |  | -index 8c1c1dc..418b2c4 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIInfoTypes.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIInfoTypes.h
 | 
	
		
			
				|  |  | -@@ -83,7 +83,7 @@ class CGUIInfoLabel
 | 
	
		
			
				|  |  | -    \param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
 | 
	
		
			
				|  |  | -    \return label (or image).
 | 
	
		
			
				|  |  | -    */  
 | 
	
		
			
				|  |  | --  CStdString GetLabel(int contextWindow, bool preferImage = false, CStdString *fallback = NULL) const;
 | 
	
		
			
				|  |  | -+  const std::string &GetLabel(int contextWindow, bool preferImage = false, CStdString *fallback = NULL) const;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   /*!
 | 
	
		
			
				|  |  | -    \brief Gets a label (or image) for a given listitem from the info manager.
 | 
	
		
			
				|  |  | -@@ -92,7 +92,7 @@ class CGUIInfoLabel
 | 
	
		
			
				|  |  | -    \param fallback if non-NULL, is set to an alternate value to use should the actual value be not appropriate. Defaults to NULL.
 | 
	
		
			
				|  |  | -    \return label (or image).
 | 
	
		
			
				|  |  | -    */
 | 
	
		
			
				|  |  | --  CStdString GetItemLabel(const CGUIListItem *item, bool preferImage = false, CStdString *fallback = NULL) const;
 | 
	
		
			
				|  |  | -+  const std::string &GetItemLabel(const CGUIListItem *item, bool preferImage = false, CStdString *fallback = NULL) const;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool IsConstant() const;
 | 
	
		
			
				|  |  | -   bool IsEmpty() const;
 | 
	
		
			
				|  |  | -@@ -132,6 +132,13 @@ class CGUIInfoLabel
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   CStdString m_fallback;
 | 
	
		
			
				|  |  | -   std::vector<CInfoPortion> m_info;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  mutable bool m_labelDirty;
 | 
	
		
			
				|  |  | -+  mutable std::string m_label;
 | 
	
		
			
				|  |  | -+  mutable std::vector<std::string> m_labelPortions;
 | 
	
		
			
				|  |  | -+  mutable bool m_itemLabelDirty;
 | 
	
		
			
				|  |  | -+  mutable std::string m_itemLabel;
 | 
	
		
			
				|  |  | -+  mutable std::vector<std::string> m_itemLabelPortions;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 3d5a1912ffd4556ec09208fea50d2a2919775c9f Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Tue, 10 Dec 2013 01:12:31 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 17/94] De-duplication of string cache for non-item and item
 | 
	
		
			
				|  |  | - labels
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIInfoTypes.cpp | 50 +++++++++++++++++++++++++-------------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIInfoTypes.h   |  4 +---
 | 
	
		
			
				|  |  | - 2 files changed, 29 insertions(+), 25 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIInfoTypes.cpp b/xbmc/guilib/GUIInfoTypes.cpp
 | 
	
		
			
				|  |  | -index d78c26a..8bd131f 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIInfoTypes.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIInfoTypes.cpp
 | 
	
		
			
				|  |  | -@@ -121,7 +121,7 @@ void CGUIInfoColor::Parse(const CStdString &label, int context)
 | 
	
		
			
				|  |  | -     m_color = g_colorManager.GetColor(label);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --CGUIInfoLabel::CGUIInfoLabel()
 | 
	
		
			
				|  |  | -+CGUIInfoLabel::CGUIInfoLabel() : m_labelDirty(true)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -178,7 +178,10 @@ const std::string &CGUIInfoLabel::GetLabel(int contextWindow, bool preferImage,
 | 
	
		
			
				|  |  | -     if (m_label.empty())  // empty label, use the fallback
 | 
	
		
			
				|  |  | -       m_label = m_fallback;
 | 
	
		
			
				|  |  | -     m_labelDirty = false;
 | 
	
		
			
				|  |  | -+    m_isLabelOfListItem = false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    assert(m_isLabelOfListItem == false);
 | 
	
		
			
				|  |  | -   return m_label;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -186,12 +189,15 @@ const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool pr
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (!item->IsFileItem())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if (m_itemLabelDirty)
 | 
	
		
			
				|  |  | -+    if (m_labelDirty)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      m_itemLabel = "";
 | 
	
		
			
				|  |  | --      m_itemLabelDirty = false;
 | 
	
		
			
				|  |  | -+      m_label = "";
 | 
	
		
			
				|  |  | -+      m_labelDirty = false;
 | 
	
		
			
				|  |  | -+      m_isLabelOfListItem = true;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    return m_itemLabel;
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+      assert(m_isLabelOfListItem == true);
 | 
	
		
			
				|  |  | -+    return m_label;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -203,38 +209,41 @@ const std::string &CGUIInfoLabel::GetItemLabel(const CGUIListItem *item, bool pr
 | 
	
		
			
				|  |  | -         infoLabel = g_infoManager.GetItemImage((const CFileItem *)item, portion.m_info, fallback);
 | 
	
		
			
				|  |  | -       else
 | 
	
		
			
				|  |  | -         infoLabel = g_infoManager.GetItemLabel((const CFileItem *)item, portion.m_info, fallback);
 | 
	
		
			
				|  |  | --      if (j == m_itemLabelPortions.size())
 | 
	
		
			
				|  |  | --        m_itemLabelPortions.push_back(infoLabel);
 | 
	
		
			
				|  |  | --      else if (infoLabel != m_itemLabelPortions[j])
 | 
	
		
			
				|  |  | -+      if (j == m_labelPortions.size())
 | 
	
		
			
				|  |  | -+        m_labelPortions.push_back(infoLabel);
 | 
	
		
			
				|  |  | -+      else if (infoLabel != m_labelPortions[j])
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        m_itemLabelPortions[j] = infoLabel;
 | 
	
		
			
				|  |  | --        m_itemLabelDirty = true;
 | 
	
		
			
				|  |  | -+        m_labelPortions[j] = infoLabel;
 | 
	
		
			
				|  |  | -+        m_labelDirty = true;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -       j++;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  if (m_itemLabelDirty)
 | 
	
		
			
				|  |  | -+  if (m_labelDirty)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    m_itemLabel.clear();
 | 
	
		
			
				|  |  | -+    m_label.clear();
 | 
	
		
			
				|  |  | -     for (unsigned int i = 0, j = 0; i < m_info.size(); i++)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       const CInfoPortion &portion = m_info[i];
 | 
	
		
			
				|  |  | -       if (portion.m_info)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        if (!m_itemLabelPortions[j].empty())
 | 
	
		
			
				|  |  | --          m_itemLabel += portion.GetLabel(m_itemLabelPortions[j]);
 | 
	
		
			
				|  |  | -+        if (!m_labelPortions[j].empty())
 | 
	
		
			
				|  |  | -+          m_label += portion.GetLabel(m_labelPortions[j]);
 | 
	
		
			
				|  |  | -         j++;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -       else
 | 
	
		
			
				|  |  | -       { // no info, so just append the prefix
 | 
	
		
			
				|  |  | --        m_itemLabel += portion.m_prefix;
 | 
	
		
			
				|  |  | -+        m_label += portion.m_prefix;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    if (m_itemLabel.empty())
 | 
	
		
			
				|  |  | --      m_itemLabel = m_fallback;
 | 
	
		
			
				|  |  | --    m_itemLabelDirty = false;
 | 
	
		
			
				|  |  | -+    if (m_label.empty())
 | 
	
		
			
				|  |  | -+      m_label = m_fallback;
 | 
	
		
			
				|  |  | -+    m_labelDirty = false;
 | 
	
		
			
				|  |  | -+    m_isLabelOfListItem = true;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  return m_itemLabel;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    assert(m_isLabelOfListItem == true);
 | 
	
		
			
				|  |  | -+  return m_label;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool CGUIInfoLabel::IsEmpty() const
 | 
	
		
			
				|  |  | -@@ -328,9 +337,6 @@ void CGUIInfoLabel::Parse(const CStdString &label, int context)
 | 
	
		
			
				|  |  | -   m_labelDirty = true;
 | 
	
		
			
				|  |  | -   m_label.clear();
 | 
	
		
			
				|  |  | -   m_labelPortions.clear();
 | 
	
		
			
				|  |  | --  m_itemLabelDirty = true;
 | 
	
		
			
				|  |  | --  m_itemLabel.clear();
 | 
	
		
			
				|  |  | --  m_itemLabelPortions.clear();
 | 
	
		
			
				|  |  | -   // Step 1: Replace all $LOCALIZE[number] with the real string
 | 
	
		
			
				|  |  | -   CStdString work = ReplaceLocalize(label);
 | 
	
		
			
				|  |  | -   // Step 2: Replace all $ADDON[id number] with the real string
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIInfoTypes.h b/xbmc/guilib/GUIInfoTypes.h
 | 
	
		
			
				|  |  | -index 418b2c4..6d9ebf7 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIInfoTypes.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIInfoTypes.h
 | 
	
		
			
				|  |  | -@@ -133,12 +133,10 @@ class CGUIInfoLabel
 | 
	
		
			
				|  |  | -   CStdString m_fallback;
 | 
	
		
			
				|  |  | -   std::vector<CInfoPortion> m_info;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  mutable bool m_isLabelOfListItem;
 | 
	
		
			
				|  |  | -   mutable bool m_labelDirty;
 | 
	
		
			
				|  |  | -   mutable std::string m_label;
 | 
	
		
			
				|  |  | -   mutable std::vector<std::string> m_labelPortions;
 | 
	
		
			
				|  |  | --  mutable bool m_itemLabelDirty;
 | 
	
		
			
				|  |  | --  mutable std::string m_itemLabel;
 | 
	
		
			
				|  |  | --  mutable std::vector<std::string> m_itemLabelPortions;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 1427baf4395b760227afbef8e17956ba251f2fbe Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Fri, 21 Feb 2014 15:16:13 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 18/94] Faster and simpler portable implementation of
 | 
	
		
			
				|  |  | - MathUtils::round_int().
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Much as I like a bit of inline assembler, I have also removed the ARM versions
 | 
	
		
			
				|  |  | -of MathUtils::truncate_int() and MathUtils::round_int(). The former was just
 | 
	
		
			
				|  |  | -how any sane compiler should have assembled a cast from double to signed int
 | 
	
		
			
				|  |  | -anyway. The latter was a much too complicated way to achieve the desired
 | 
	
		
			
				|  |  | -effect, and was switched out in most ARM builds anyway in favour of the old
 | 
	
		
			
				|  |  | -portable implementation that used floor().
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Verified that MathUtils::test() still passes, and that GCC is now able to
 | 
	
		
			
				|  |  | -inline MathUtils::round_int(), where it didn't previously.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -I tested on a Raspberry Pi with the default theme, displaying the front page
 | 
	
		
			
				|  |  | -with the RSS ticker enabled. This saturates the CPU, so I'm measuring the
 | 
	
		
			
				|  |  | -improvement using the debug window's FPS figure. This patch improves this from
 | 
	
		
			
				|  |  | -~50.8 FPS to ~52.6 FPS.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/utils/MathUtils.h | 129 +++++++++++++++++++++++--------------------------
 | 
	
		
			
				|  |  | - 1 file changed, 61 insertions(+), 68 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/utils/MathUtils.h b/xbmc/utils/MathUtils.h
 | 
	
		
			
				|  |  | -index 96af9f4..0dae77d 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/utils/MathUtils.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/utils/MathUtils.h
 | 
	
		
			
				|  |  | -@@ -34,17 +34,13 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(__ppc__) || \
 | 
	
		
			
				|  |  | -     defined(__powerpc__) || \
 | 
	
		
			
				|  |  | --   (defined(TARGET_DARWIN_IOS) && defined(__llvm__)) || \
 | 
	
		
			
				|  |  | --   (defined(TARGET_ANDROID) && defined(__arm__)) || \
 | 
	
		
			
				|  |  | --    defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | -+    defined(__arm__)
 | 
	
		
			
				|  |  | -   #define DISABLE_MATHUTILS_ASM_ROUND_INT
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(__ppc__) || \
 | 
	
		
			
				|  |  | -     defined(__powerpc__) || \
 | 
	
		
			
				|  |  | --   (defined(TARGET_DARWIN) && defined(__llvm__)) || \
 | 
	
		
			
				|  |  | --   (defined(TARGET_ANDROID) && defined(__arm__)) || \
 | 
	
		
			
				|  |  | --    defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | -+    defined(__arm__)
 | 
	
		
			
				|  |  | -   #define DISABLE_MATHUTILS_ASM_TRUNCATE_INT
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -73,60 +69,63 @@ namespace MathUtils
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
 | 
	
		
			
				|  |  | -     assert(x < static_cast<double>(INT_MAX / 2) + 1.0);
 | 
	
		
			
				|  |  | --    const float round_to_nearest = 0.5f;
 | 
	
		
			
				|  |  | --    int i;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(DISABLE_MATHUTILS_ASM_ROUND_INT)
 | 
	
		
			
				|  |  | --    i = floor(x + round_to_nearest);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#elif defined(__arm__)
 | 
	
		
			
				|  |  | --    // From 'ARM-v7-M Architecture Reference Manual' page A7-569:
 | 
	
		
			
				|  |  | --    //  "The floating-point to integer operation (vcvt) [normally] uses the Round towards Zero rounding mode"
 | 
	
		
			
				|  |  | --    // Because of this...we must use some less-than-straightforward logic to perform this operation without
 | 
	
		
			
				|  |  | --    //  changing the rounding mode flags
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    /* The assembly below implements the following logic:
 | 
	
		
			
				|  |  | --     if (x < 0)
 | 
	
		
			
				|  |  | --       inc = -0.5f
 | 
	
		
			
				|  |  | --     else
 | 
	
		
			
				|  |  | --       inc = 0.5f
 | 
	
		
			
				|  |  | --     int_val = trunc(x+inc);
 | 
	
		
			
				|  |  | --     err = x - int_val;
 | 
	
		
			
				|  |  | --     if (err == 0.5f)
 | 
	
		
			
				|  |  | --       int_val++;
 | 
	
		
			
				|  |  | --     return int_val;
 | 
	
		
			
				|  |  | --    */
 | 
	
		
			
				|  |  | -+    /* This implementation warrants some further explanation.
 | 
	
		
			
				|  |  | -+     *
 | 
	
		
			
				|  |  | -+     * First, a couple of notes on rounding:
 | 
	
		
			
				|  |  | -+     * 1) C casts from float/double to integer round towards zero.
 | 
	
		
			
				|  |  | -+     * 2) Float/double additions are rounded according to the normal rules,
 | 
	
		
			
				|  |  | -+     *    in other words: on some architectures, it's fixed at compile-time,
 | 
	
		
			
				|  |  | -+     *    and on others it can be set using fesetround()). The following
 | 
	
		
			
				|  |  | -+     *    analysis assumes round-to-nearest with ties rounding to even. This
 | 
	
		
			
				|  |  | -+     *    is a fairly sensible choice, and is the default with ARM VFP.
 | 
	
		
			
				|  |  | -+     *
 | 
	
		
			
				|  |  | -+     * What this function wants is round-to-nearest with ties rounding to
 | 
	
		
			
				|  |  | -+     * +infinity. This isn't an IEEE rounding mode, even if we could guarantee
 | 
	
		
			
				|  |  | -+     * that all architectures supported fesetround(), which they don't. Instead,
 | 
	
		
			
				|  |  | -+     * this adds an offset of 2147483648.5 (= 0x80000000.8p0), then casts to
 | 
	
		
			
				|  |  | -+     * an unsigned int (crucially, all possible inputs are now in a range where
 | 
	
		
			
				|  |  | -+     * round to zero acts the same as round to -infinity) and then subtracts
 | 
	
		
			
				|  |  | -+     * 0x80000000 in the integer domain. The 0.5 component of the offset
 | 
	
		
			
				|  |  | -+     * converts what is effectively a round down into a round to nearest, with
 | 
	
		
			
				|  |  | -+     * ties rounding up, as desired.
 | 
	
		
			
				|  |  | -+     *
 | 
	
		
			
				|  |  | -+     * There is a catch, that because there is a double rounding, there is a
 | 
	
		
			
				|  |  | -+     * small region where the input falls just *below* a tie, where the addition
 | 
	
		
			
				|  |  | -+     * of the offset causes a round *up* to an exact integer, due to the finite
 | 
	
		
			
				|  |  | -+     * level of precision available in floating point. You need to be aware of
 | 
	
		
			
				|  |  | -+     * this when calling this function, although at present it is not believed
 | 
	
		
			
				|  |  | -+     * that XBMC ever attempts to round numbers in this window.
 | 
	
		
			
				|  |  | -+     *
 | 
	
		
			
				|  |  | -+     * It is worth proving the size of the affected window. Recall that double
 | 
	
		
			
				|  |  | -+     * precision employs a mantissa of 52 bits.
 | 
	
		
			
				|  |  | -+     * 1) For all inputs -0.5 <= x <= INT_MAX
 | 
	
		
			
				|  |  | -+     *    Once the offset is applied, the most significant binary digit in the
 | 
	
		
			
				|  |  | -+     *    floating-point representation is +2^31.
 | 
	
		
			
				|  |  | -+     *    At this magnitude, the smallest step representable in double precision
 | 
	
		
			
				|  |  | -+     *    is 2^31 / 2^52 = 0.000000476837158203125
 | 
	
		
			
				|  |  | -+     *    So the size of the range which is rounded up due to the addition is
 | 
	
		
			
				|  |  | -+     *    half the size of this step, or 0.0000002384185791015625
 | 
	
		
			
				|  |  | -+     *
 | 
	
		
			
				|  |  | -+     * 2) For all inputs INT_MIN/2 < x < -0.5
 | 
	
		
			
				|  |  | -+     *    Once the offset is applied, the most significant binary digit in the
 | 
	
		
			
				|  |  | -+     *    floating-point representation is +2^30.
 | 
	
		
			
				|  |  | -+     *    At this magnitude, the smallest step representable in double precision
 | 
	
		
			
				|  |  | -+     *    is 2^30 / 2^52 = 0.0000002384185791015625
 | 
	
		
			
				|  |  | -+     *    So the size of the range which is rounded up due to the addition is
 | 
	
		
			
				|  |  | -+     *    half the size of this step, or 0.00000011920928955078125
 | 
	
		
			
				|  |  | -+     *
 | 
	
		
			
				|  |  | -+     * 3) For all inputs INT_MIN <= x <= INT_MIN/2
 | 
	
		
			
				|  |  | -+     *    The representation once the offset is applied has equal or greater
 | 
	
		
			
				|  |  | -+     *    precision than the input, so the addition does not cause rounding.
 | 
	
		
			
				|  |  | -+     */
 | 
	
		
			
				|  |  | -+    return ((unsigned int) (x + 0x80000000.8p0)) - 0x80000000;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    __asm__ __volatile__ (
 | 
	
		
			
				|  |  | --#if defined(__ARM_PCS_VFP)
 | 
	
		
			
				|  |  | --      "fconstd d1,#%G[rnd_val]     \n\t" // Copy round_to_nearest into a working register (d1 = 0.5)
 | 
	
		
			
				|  |  | - #else
 | 
	
		
			
				|  |  | --      "vmov.F64 d1,%[rnd_val]      \n\t"
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --      "fcmpezd %P[value]           \n\t" // Check value against zero (value == 0?)
 | 
	
		
			
				|  |  | --      "fmstat                      \n\t" // Copy the floating-point status flags into the general-purpose status flags
 | 
	
		
			
				|  |  | --      "it mi                       \n\t"
 | 
	
		
			
				|  |  | --      "vnegmi.F64 d1, d1           \n\t" // if N-flag is set, negate round_to_nearest (if (value < 0) d1 = -1 * d1)
 | 
	
		
			
				|  |  | --      "vadd.F64 d1,%P[value],d1    \n\t" // Add round_to_nearest to value, store result in working register (d1 += value)
 | 
	
		
			
				|  |  | --      "vcvt.S32.F64 s3,d1          \n\t" // Truncate(round towards zero) (s3 = (int)d1)
 | 
	
		
			
				|  |  | --      "vmov %[result],s3           \n\t" // Store the integer result in a general-purpose register (result = s3)
 | 
	
		
			
				|  |  | --      "vcvt.F64.S32 d1,s3          \n\t" // Convert back to floating-point (d1 = (double)s3)
 | 
	
		
			
				|  |  | --      "vsub.F64 d1,%P[value],d1    \n\t" // Calculate the error (d1 = value - d1)
 | 
	
		
			
				|  |  | --#if defined(__ARM_PCS_VFP)
 | 
	
		
			
				|  |  | --      "fconstd d2,#%G[rnd_val]     \n\t" // d2 = 0.5;
 | 
	
		
			
				|  |  | --#else
 | 
	
		
			
				|  |  | --      "vmov.F64 d2,%[rnd_val]      \n\t"
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --      "fcmped d1, d2               \n\t" // (d1 == 0.5?)
 | 
	
		
			
				|  |  | --      "fmstat                      \n\t" // Copy the floating-point status flags into the general-purpose status flags
 | 
	
		
			
				|  |  | --      "it eq                       \n\t"
 | 
	
		
			
				|  |  | --      "addeq %[result],#1          \n\t" // (if (d1 == d2) result++;)
 | 
	
		
			
				|  |  | --      : [result] "=r"(i)                                  // Outputs
 | 
	
		
			
				|  |  | --      : [rnd_val] "Dv" (round_to_nearest), [value] "w"(x) // Inputs
 | 
	
		
			
				|  |  | --      : "d1", "d2", "s3"                                  // Clobbers
 | 
	
		
			
				|  |  | --    );
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#elif defined(__SSE2__)
 | 
	
		
			
				|  |  | -+    const float round_to_nearest = 0.5f;
 | 
	
		
			
				|  |  | -+    int i;
 | 
	
		
			
				|  |  | -+#if defined(__SSE2__)
 | 
	
		
			
				|  |  | -     const float round_dn_to_nearest = 0.4999999f;
 | 
	
		
			
				|  |  | -     i = (x > 0) ? _mm_cvttsd_si32(_mm_set_sd(x + round_to_nearest)) : _mm_cvttsd_si32(_mm_set_sd(x - round_dn_to_nearest));
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -150,8 +149,8 @@ namespace MathUtils
 | 
	
		
			
				|  |  | -     );
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -     return i;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   /*! \brief Truncate to nearest integer.
 | 
	
		
			
				|  |  | -@@ -165,20 +164,13 @@ namespace MathUtils
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     assert(x > static_cast<double>(INT_MIN / 2) - 1.0);
 | 
	
		
			
				|  |  | -     assert(x < static_cast<double>(INT_MAX / 2) + 1.0);
 | 
	
		
			
				|  |  | --    int i;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(DISABLE_MATHUTILS_ASM_TRUNCATE_INT)
 | 
	
		
			
				|  |  | --    return i = (int)x;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#elif defined(__arm__)
 | 
	
		
			
				|  |  | --    __asm__ __volatile__ (
 | 
	
		
			
				|  |  | --      "vcvt.S32.F64 %[result],%P[value]   \n\t" // Truncate(round towards zero) and store the result
 | 
	
		
			
				|  |  | --      : [result] "=w"(i)                        // Outputs
 | 
	
		
			
				|  |  | --      : [value] "w"(x)                          // Inputs
 | 
	
		
			
				|  |  | --    );
 | 
	
		
			
				|  |  | --    return i;
 | 
	
		
			
				|  |  | -+    return x;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --#elif defined(TARGET_WINDOWS)
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -+    int i;
 | 
	
		
			
				|  |  | -+#if defined(TARGET_WINDOWS)
 | 
	
		
			
				|  |  | -     const float round_towards_m_i = -0.5f;
 | 
	
		
			
				|  |  | -     __asm
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -@@ -204,6 +196,7 @@ namespace MathUtils
 | 
	
		
			
				|  |  | -     if (x < 0)
 | 
	
		
			
				|  |  | -       i = -i;
 | 
	
		
			
				|  |  | -     return (i);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   inline int64_t abs(int64_t a)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 0ad4df440ea225cc951a65bf9553b1f00f416d85 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 11 Dec 2013 17:21:54 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 19/94] Move the reference-counting of Begin and End calls from
 | 
	
		
			
				|  |  | - DX and GL source files into GUIFontTTF.cpp.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp   |  21 ++++++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h     |   6 ++-
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFDX.cpp |  79 +++++++++++++----------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFDX.h   |   4 +-
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp | 118 +++++++++++++++++++------------------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.h   |   4 +-
 | 
	
		
			
				|  |  | - 6 files changed, 117 insertions(+), 115 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 9c8e516..90b9c4a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -309,6 +309,27 @@ bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float as
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+void CGUIFontTTFBase::Begin()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_vertex_count = 0;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  // Keep track of the nested begin/end calls.
 | 
	
		
			
				|  |  | -+  m_nestedBeginCount++;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CGUIFontTTFBase::End()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (m_nestedBeginCount == 0)
 | 
	
		
			
				|  |  | -+    return;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (--m_nestedBeginCount > 0)
 | 
	
		
			
				|  |  | -+    return;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LastEnd();
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors, const vecText &text, uint32_t alignment, float maxPixelWidth, bool scrolling)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   Begin();
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index 9723a43..c1c4507 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -77,8 +77,8 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool Load(const CStdString& strFilename, float height = 20.0f, float aspect = 1.0f, float lineSpacing = 1.0f, bool border = false);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  virtual void Begin() = 0;
 | 
	
		
			
				|  |  | --  virtual void End() = 0;
 | 
	
		
			
				|  |  | -+  void Begin();
 | 
	
		
			
				|  |  | -+  void End();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   const CStdString& GetFileName() const { return m_strFileName; };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -169,6 +169,8 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   CStdString m_strFileName;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -+  virtual bool FirstBegin() = 0;
 | 
	
		
			
				|  |  | -+  virtual void LastEnd() = 0;
 | 
	
		
			
				|  |  | -   CGUIFontTTFBase(const CGUIFontTTFBase&);
 | 
	
		
			
				|  |  | -   CGUIFontTTFBase& operator=(const CGUIFontTTFBase&);
 | 
	
		
			
				|  |  | -   int m_referenceCount;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp
 | 
	
		
			
				|  |  | -index e3eba24..2f90668 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFDX.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFDX.cpp
 | 
	
		
			
				|  |  | -@@ -51,65 +51,56 @@ CGUIFontTTFDX::~CGUIFontTTFDX(void)
 | 
	
		
			
				|  |  | -   free(m_index);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CGUIFontTTFDX::Begin()
 | 
	
		
			
				|  |  | -+bool CGUIFontTTFDX::FirstBegin()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (pD3DDevice == NULL)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, __FUNCTION__" - failed to get Direct3D device");
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (m_nestedBeginCount == 0 && pD3DDevice != NULL && m_texture != NULL)
 | 
	
		
			
				|  |  | -+  int unit = 0;
 | 
	
		
			
				|  |  | -+  // just have to blit from our texture.
 | 
	
		
			
				|  |  | -+  m_texture->BindToUnit(unit);
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
 | 
	
		
			
				|  |  | -+  unit++;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if(g_Windowing.UseLimitedColor())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    int unit = 0;
 | 
	
		
			
				|  |  | --    // just have to blit from our texture.
 | 
	
		
			
				|  |  | --    m_texture->BindToUnit(unit);
 | 
	
		
			
				|  |  | --    pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_SELECTARG1 ); // only use diffuse
 | 
	
		
			
				|  |  | --    pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_DIFFUSE);
 | 
	
		
			
				|  |  | --    pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_MODULATE );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
 | 
	
		
			
				|  |  | --    pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE);
 | 
	
		
			
				|  |  | -+    pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP  , D3DTOP_ADD );
 | 
	
		
			
				|  |  | -+    pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ;
 | 
	
		
			
				|  |  | -+    pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) );
 | 
	
		
			
				|  |  | -+    pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR );
 | 
	
		
			
				|  |  | -     unit++;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if(g_Windowing.UseLimitedColor())
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP  , D3DTOP_ADD );
 | 
	
		
			
				|  |  | --      pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG1, D3DTA_CURRENT) ;
 | 
	
		
			
				|  |  | --      pD3DDevice->SetRenderState( D3DRS_TEXTUREFACTOR, D3DCOLOR_RGBA(16,16,16,0) );
 | 
	
		
			
				|  |  | --      pD3DDevice->SetTextureStageState( unit, D3DTSS_COLORARG2, D3DTA_TFACTOR );
 | 
	
		
			
				|  |  | --      unit++;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    // no other texture stages needed
 | 
	
		
			
				|  |  | --    pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE);
 | 
	
		
			
				|  |  | --    pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
 | 
	
		
			
				|  |  | --    pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
 | 
	
		
			
				|  |  | --    m_vertex_count = 0;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // Keep track of the nested begin/end calls.
 | 
	
		
			
				|  |  | --  m_nestedBeginCount++;
 | 
	
		
			
				|  |  | -+  // no other texture stages needed
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetTextureStageState( unit, D3DTSS_COLOROP, D3DTOP_DISABLE);
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetTextureStageState( unit, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_ZENABLE, FALSE );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_FOGENABLE, FALSE );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_FILLMODE, D3DFILL_SOLID );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_CULLMODE, D3DCULL_NONE );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_SRCBLEND, D3DBLEND_SRCALPHA );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA );
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetRenderState( D3DRS_LIGHTING, FALSE);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  pD3DDevice->SetFVF(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CGUIFontTTFDX::End()
 | 
	
		
			
				|  |  | -+void CGUIFontTTFDX::LastEnd()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (m_nestedBeginCount == 0)
 | 
	
		
			
				|  |  | --    return;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (--m_nestedBeginCount > 0)
 | 
	
		
			
				|  |  | --    return;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   if (m_vertex_count == 0)
 | 
	
		
			
				|  |  | -     return;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFDX.h b/xbmc/guilib/GUIFontTTFDX.h
 | 
	
		
			
				|  |  | -index 0431085..17dfefe 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFDX.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFDX.h
 | 
	
		
			
				|  |  | -@@ -41,8 +41,8 @@ class CGUIFontTTFDX : public CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   CGUIFontTTFDX(const CStdString& strFileName);
 | 
	
		
			
				|  |  | -   virtual ~CGUIFontTTFDX(void);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  virtual void Begin();
 | 
	
		
			
				|  |  | --  virtual void End();
 | 
	
		
			
				|  |  | -+  virtual bool FirstBegin();
 | 
	
		
			
				|  |  | -+  virtual void LastEnd();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index 3358a5a..93b7ea6 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -50,90 +50,78 @@ CGUIFontTTFGL::~CGUIFontTTFGL(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CGUIFontTTFGL::Begin()
 | 
	
		
			
				|  |  | -+bool CGUIFontTTFGL::FirstBegin()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if (m_nestedBeginCount == 0 && m_texture != NULL)
 | 
	
		
			
				|  |  | -+  if (!m_bTextureLoaded)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if (!m_bTextureLoaded)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      // Have OpenGL generate a texture object handle for us
 | 
	
		
			
				|  |  | --      glGenTextures(1, (GLuint*) &m_nTexture);
 | 
	
		
			
				|  |  | -+    // Have OpenGL generate a texture object handle for us
 | 
	
		
			
				|  |  | -+    glGenTextures(1, (GLuint*) &m_nTexture);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      // Bind the texture object
 | 
	
		
			
				|  |  | --      glBindTexture(GL_TEXTURE_2D, m_nTexture);
 | 
	
		
			
				|  |  | -+    // Bind the texture object
 | 
	
		
			
				|  |  | -+    glBindTexture(GL_TEXTURE_2D, m_nTexture);
 | 
	
		
			
				|  |  | - #ifdef HAS_GL
 | 
	
		
			
				|  |  | --      glEnable(GL_TEXTURE_2D);
 | 
	
		
			
				|  |  | -+    glEnable(GL_TEXTURE_2D);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | --      // Set the texture's stretching properties
 | 
	
		
			
				|  |  | --      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
	
		
			
				|  |  | --      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
	
		
			
				|  |  | -+    // Set the texture's stretching properties
 | 
	
		
			
				|  |  | -+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
	
		
			
				|  |  | -+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      // Set the texture image -- THIS WORKS, so the pixels must be wrong.
 | 
	
		
			
				|  |  | --      glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
 | 
	
		
			
				|  |  | --                   GL_ALPHA, GL_UNSIGNED_BYTE, m_texture->GetPixels());
 | 
	
		
			
				|  |  | -+    // Set the texture image -- THIS WORKS, so the pixels must be wrong.
 | 
	
		
			
				|  |  | -+    glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, m_texture->GetWidth(), m_texture->GetHeight(), 0,
 | 
	
		
			
				|  |  | -+                 GL_ALPHA, GL_UNSIGNED_BYTE, m_texture->GetPixels());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      VerifyGLState();
 | 
	
		
			
				|  |  | --      m_bTextureLoaded = true;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    VerifyGLState();
 | 
	
		
			
				|  |  | -+    m_bTextureLoaded = true;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    // Turn Blending On
 | 
	
		
			
				|  |  | --    glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
 | 
	
		
			
				|  |  | --    glEnable(GL_BLEND);
 | 
	
		
			
				|  |  | -+  // Turn Blending On
 | 
	
		
			
				|  |  | -+  glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA, GL_ONE);
 | 
	
		
			
				|  |  | -+  glEnable(GL_BLEND);
 | 
	
		
			
				|  |  | - #ifdef HAS_GL
 | 
	
		
			
				|  |  | --    glEnable(GL_TEXTURE_2D);
 | 
	
		
			
				|  |  | -+  glEnable(GL_TEXTURE_2D);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | --    glBindTexture(GL_TEXTURE_2D, m_nTexture);
 | 
	
		
			
				|  |  | -+  glBindTexture(GL_TEXTURE_2D, m_nTexture);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #ifdef HAS_GL
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
 | 
	
		
			
				|  |  | --    glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 | 
	
		
			
				|  |  | --    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 | 
	
		
			
				|  |  | --    VerifyGLState();
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_RGB,GL_REPLACE);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PRIMARY_COLOR);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE0);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_PRIMARY_COLOR);
 | 
	
		
			
				|  |  | -+  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 | 
	
		
			
				|  |  | -+  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 | 
	
		
			
				|  |  | -+  VerifyGLState();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if(g_Windowing.UseLimitedColor())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    glActiveTexture(GL_TEXTURE1);
 | 
	
		
			
				|  |  | -+    glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
 | 
	
		
			
				|  |  | -+    glEnable(GL_TEXTURE_2D);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    if(g_Windowing.UseLimitedColor())
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      glActiveTexture(GL_TEXTURE1);
 | 
	
		
			
				|  |  | --      glBindTexture(GL_TEXTURE_2D, m_nTexture); // dummy bind
 | 
	
		
			
				|  |  | --      glEnable(GL_TEXTURE_2D);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f};
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE);
 | 
	
		
			
				|  |  | --      glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB      , GL_ADD);
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB      , GL_PREVIOUS);
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB      , GL_CONSTANT);
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB     , GL_SRC_COLOR);
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB     , GL_SRC_COLOR);
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA    , GL_REPLACE);
 | 
	
		
			
				|  |  | --      glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA    , GL_PREVIOUS);
 | 
	
		
			
				|  |  | --      VerifyGLState();
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    const GLfloat rgba[4] = {16.0f / 255.0f, 16.0f / 255.0f, 16.0f / 255.0f, 0.0f};
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE , GL_COMBINE);
 | 
	
		
			
				|  |  | -+    glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB      , GL_ADD);
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_RGB      , GL_PREVIOUS);
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE1_RGB      , GL_CONSTANT);
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB     , GL_SRC_COLOR);
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB     , GL_SRC_COLOR);
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA    , GL_REPLACE);
 | 
	
		
			
				|  |  | -+    glTexEnvi (GL_TEXTURE_ENV, GL_SOURCE0_ALPHA    , GL_PREVIOUS);
 | 
	
		
			
				|  |  | -+    VerifyGLState();
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #else
 | 
	
		
			
				|  |  | --    g_Windowing.EnableGUIShader(SM_FONTS);
 | 
	
		
			
				|  |  | -+  g_Windowing.EnableGUIShader(SM_FONTS);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    m_vertex_count = 0;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  // Keep track of the nested begin/end calls.
 | 
	
		
			
				|  |  | --  m_nestedBeginCount++;
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CGUIFontTTFGL::End()
 | 
	
		
			
				|  |  | -+void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if (m_nestedBeginCount == 0)
 | 
	
		
			
				|  |  | --    return;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (--m_nestedBeginCount > 0)
 | 
	
		
			
				|  |  | --    return;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - #ifdef HAS_GL
 | 
	
		
			
				|  |  | -   glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -index a0dacba..6736cf7 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -@@ -41,8 +41,8 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   CGUIFontTTFGL(const CStdString& strFileName);
 | 
	
		
			
				|  |  | -   virtual ~CGUIFontTTFGL(void);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  virtual void Begin();
 | 
	
		
			
				|  |  | --  virtual void End();
 | 
	
		
			
				|  |  | -+  virtual bool FirstBegin();
 | 
	
		
			
				|  |  | -+  virtual void LastEnd();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 427373ae5bb96489afb22529714c16e8f82c2195 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 11 Dec 2013 18:47:54 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 20/94] Convert CGUIFontTTFBase::m_vertex to be managed as a
 | 
	
		
			
				|  |  | - std::vector. Also retired CGUIFontTTFBase::m_vertex_count and
 | 
	
		
			
				|  |  | - CGUIFontTTFBase::m_vertex_size because these can be derived from vector
 | 
	
		
			
				|  |  | - member functions.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp   | 29 +++++------------------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h     |  4 +---
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFDX.cpp | 12 ++++++------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp | 12 ++++++------
 | 
	
		
			
				|  |  | - 4 files changed, 18 insertions(+), 39 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 90b9c4a..3f219d9 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -139,8 +139,7 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
 | 
	
		
			
				|  |  | -   m_nestedBeginCount = 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_bTextureLoaded = false;
 | 
	
		
			
				|  |  | --  m_vertex_size   = 4*1024;
 | 
	
		
			
				|  |  | --  m_vertex        = (SVertex*)malloc(m_vertex_size * sizeof(SVertex));
 | 
	
		
			
				|  |  | -+  m_vertex.reserve(4*1024);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_face = NULL;
 | 
	
		
			
				|  |  | -   m_stroker = NULL;
 | 
	
		
			
				|  |  | -@@ -155,7 +154,6 @@ CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
 | 
	
		
			
				|  |  | -   m_textureScaleX = m_textureScaleY = 0.0;
 | 
	
		
			
				|  |  | -   m_ellipsesWidth = m_height = 0.0f;
 | 
	
		
			
				|  |  | -   m_color = 0;
 | 
	
		
			
				|  |  | --  m_vertex_count = 0;
 | 
	
		
			
				|  |  | -   m_nTexture = 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -216,9 +214,7 @@ void CGUIFontTTFBase::Clear()
 | 
	
		
			
				|  |  | -     g_freeTypeLibrary.ReleaseStroker(m_stroker);
 | 
	
		
			
				|  |  | -   m_stroker = NULL;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  free(m_vertex);
 | 
	
		
			
				|  |  | --  m_vertex = NULL;
 | 
	
		
			
				|  |  | --  m_vertex_count = 0;
 | 
	
		
			
				|  |  | -+  m_vertex.clear();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool CGUIFontTTFBase::Load(const CStdString& strFilename, float height, float aspect, float lineSpacing, bool border)
 | 
	
		
			
				|  |  | -@@ -313,7 +309,7 @@ void CGUIFontTTFBase::Begin()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    m_vertex_count = 0;
 | 
	
		
			
				|  |  | -+    m_vertex.clear();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   // Keep track of the nested begin/end calls.
 | 
	
		
			
				|  |  | -   m_nestedBeginCount++;
 | 
	
		
			
				|  |  | -@@ -746,22 +742,9 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
 | 
	
		
			
				|  |  | -   float tt = texture.y1 * m_textureScaleY;
 | 
	
		
			
				|  |  | -   float tb = texture.y2 * m_textureScaleY;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // grow the vertex buffer if required
 | 
	
		
			
				|  |  | --  if(m_vertex_count >= m_vertex_size)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_vertex_size *= 2;
 | 
	
		
			
				|  |  | --    void* old      = m_vertex;
 | 
	
		
			
				|  |  | --    m_vertex       = (SVertex*)realloc(m_vertex, m_vertex_size * sizeof(SVertex));
 | 
	
		
			
				|  |  | --    if (!m_vertex)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      free(old);
 | 
	
		
			
				|  |  | --      CLog::Log(LOGSEVERE, "%s: can't allocate %"PRIdS" bytes for texture", __FUNCTION__ , m_vertex_size * sizeof(SVertex));
 | 
	
		
			
				|  |  | --      return;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+  m_vertex.resize(m_vertex.size() + 4);
 | 
	
		
			
				|  |  | -+  SVertex* v = &m_vertex[m_vertex.size() - 4];
 | 
	
		
			
				|  |  | -   m_color = color;
 | 
	
		
			
				|  |  | --  SVertex* v = m_vertex + m_vertex_count;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   unsigned char r = GET_R(color)
 | 
	
		
			
				|  |  | -               , g = GET_G(color)
 | 
	
		
			
				|  |  | -@@ -828,8 +811,6 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
 | 
	
		
			
				|  |  | -   v[3].y = y[2];
 | 
	
		
			
				|  |  | -   v[3].z = z[2];
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_vertex_count+=4;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - // Oblique code - original taken from freetype2 (ftsynth.c)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index c1c4507..35e3cf9 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -157,9 +157,7 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   bool m_bTextureLoaded;
 | 
	
		
			
				|  |  | -   unsigned int m_nTexture;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  SVertex* m_vertex;
 | 
	
		
			
				|  |  | --  int      m_vertex_count;
 | 
	
		
			
				|  |  | --  int      m_vertex_size;
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> m_vertex;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   float    m_textureScaleX;
 | 
	
		
			
				|  |  | -   float    m_textureScaleY;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFDX.cpp b/xbmc/guilib/GUIFontTTFDX.cpp
 | 
	
		
			
				|  |  | -index 2f90668..6ef8984 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFDX.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFDX.cpp
 | 
	
		
			
				|  |  | -@@ -101,17 +101,17 @@ void CGUIFontTTFDX::LastEnd()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   LPDIRECT3DDEVICE9 pD3DDevice = g_Windowing.Get3DDevice();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (m_vertex_count == 0)
 | 
	
		
			
				|  |  | -+  if (m_vertex.size() == 0)
 | 
	
		
			
				|  |  | -     return;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  unsigned index_size = m_vertex_size * 6 / 4;
 | 
	
		
			
				|  |  | -+  unsigned index_size = m_vertex.capacity() * 6 / 4;
 | 
	
		
			
				|  |  | -   if(m_index_size < index_size)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     uint16_t* id  = (uint16_t*)calloc(index_size, sizeof(uint16_t));
 | 
	
		
			
				|  |  | -     if(id == NULL)
 | 
	
		
			
				|  |  | -       return;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    for(int i = 0, b = 0; i < m_vertex_size; i += 4, b += 6)
 | 
	
		
			
				|  |  | -+    for(int i = 0, b = 0; i < m_vertex.capacity(); i += 4, b += 6)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       id[b+0] = i + 0;
 | 
	
		
			
				|  |  | -       id[b+1] = i + 1;
 | 
	
		
			
				|  |  | -@@ -140,11 +140,11 @@ void CGUIFontTTFDX::LastEnd()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   pD3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST
 | 
	
		
			
				|  |  | -                                     , 0
 | 
	
		
			
				|  |  | --                                    , m_vertex_count
 | 
	
		
			
				|  |  | --                                    , m_vertex_count / 2
 | 
	
		
			
				|  |  | -+                                    , m_vertex.size()
 | 
	
		
			
				|  |  | -+                                    , m_vertex.size() / 2
 | 
	
		
			
				|  |  | -                                     , m_index
 | 
	
		
			
				|  |  | -                                     , D3DFMT_INDEX16
 | 
	
		
			
				|  |  | --                                    , m_vertex
 | 
	
		
			
				|  |  | -+                                    , &m_vertex[0]
 | 
	
		
			
				|  |  | -                                     , sizeof(SVertex));
 | 
	
		
			
				|  |  | -   pD3DDevice->SetTransform(D3DTS_WORLD, &orig);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index 93b7ea6..a4e8571 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -125,13 +125,13 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | - #ifdef HAS_GL
 | 
	
		
			
				|  |  | -   glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  glColorPointer   (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | --  glVertexPointer  (3, GL_FLOAT        , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | --  glTexCoordPointer(2, GL_FLOAT        , sizeof(SVertex), (char*)m_vertex + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+  glColorPointer   (4, GL_UNSIGNED_BYTE, sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | -+  glVertexPointer  (3, GL_FLOAT        , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | -+  glTexCoordPointer(2, GL_FLOAT        , sizeof(SVertex), (char*)&m_vertex[0] + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -   glEnableClientState(GL_COLOR_ARRAY);
 | 
	
		
			
				|  |  | -   glEnableClientState(GL_VERTEX_ARRAY);
 | 
	
		
			
				|  |  | -   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 | 
	
		
			
				|  |  | --  glDrawArrays(GL_QUADS, 0, m_vertex_count);
 | 
	
		
			
				|  |  | -+  glDrawArrays(GL_QUADS, 0, m_vertex.size());
 | 
	
		
			
				|  |  | -   glPopClientAttrib();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   glActiveTexture(GL_TEXTURE1);
 | 
	
		
			
				|  |  | -@@ -147,10 +147,10 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -   GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // stack object until VBOs will be used
 | 
	
		
			
				|  |  | --  std::vector<SVertex> vecVertices( 6 * (m_vertex_count / 4) );
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
 | 
	
		
			
				|  |  | -   SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  for (int i=0; i<m_vertex_count; i+=4)
 | 
	
		
			
				|  |  | -+  for (size_t i=0; i<m_vertex.size(); i+=4)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     *vertices++ = m_vertex[i];
 | 
	
		
			
				|  |  | -     *vertices++ = m_vertex[i+1];
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From a3e8e7f1055726a050e04d1e4ab61a5355cdbd6a Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Mon, 16 Dec 2013 18:58:12 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 21/94] CGUIFontTTFBase::RenderCharacter can now append to
 | 
	
		
			
				|  |  | - arbitrary vectors of vertices rather than only CGUIFontTTFBase::m_vertex
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp | 12 +++++++-----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h   |  2 +-
 | 
	
		
			
				|  |  | - 2 files changed, 8 insertions(+), 6 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 3f219d9..1aaf68b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -330,6 +330,8 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   Begin();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> &vertices = m_vertex;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // save the origin, which is scaled separately
 | 
	
		
			
				|  |  | -   m_originX = x;
 | 
	
		
			
				|  |  | -   m_originY = y;
 | 
	
		
			
				|  |  | -@@ -410,7 +412,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         for (int i = 0; i < 3; i++)
 | 
	
		
			
				|  |  | -         {
 | 
	
		
			
				|  |  | --          RenderCharacter(startX + cursorX, startY, period, color, !scrolling);
 | 
	
		
			
				|  |  | -+          RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
 | 
	
		
			
				|  |  | -           cursorX += period->advance;
 | 
	
		
			
				|  |  | -         }
 | 
	
		
			
				|  |  | -         break;
 | 
	
		
			
				|  |  | -@@ -419,7 +421,7 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | -     else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
 | 
	
		
			
				|  |  | -       break;  // exceeded max allowed width - stop rendering
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    RenderCharacter(startX + cursorX, startY, ch, color, !scrolling);
 | 
	
		
			
				|  |  | -+    RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
 | 
	
		
			
				|  |  | -     if ( alignment & XBFONT_JUSTIFIED )
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       if ((*pos & 0xffff) == L' ')
 | 
	
		
			
				|  |  | -@@ -676,7 +678,7 @@ bool CGUIFontTTFBase::CacheCharacter(wchar_t letter, uint32_t style, Character *
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX)
 | 
	
		
			
				|  |  | -+void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector<SVertex> &vertices)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   // actual image width isn't same as the character width as that is
 | 
	
		
			
				|  |  | -   // just baseline width and height should include the descent
 | 
	
		
			
				|  |  | -@@ -742,8 +744,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
 | 
	
		
			
				|  |  | -   float tt = texture.y1 * m_textureScaleY;
 | 
	
		
			
				|  |  | -   float tb = texture.y2 * m_textureScaleY;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_vertex.resize(m_vertex.size() + 4);
 | 
	
		
			
				|  |  | --  SVertex* v = &m_vertex[m_vertex.size() - 4];
 | 
	
		
			
				|  |  | -+  vertices.resize(vertices.size() + 4);
 | 
	
		
			
				|  |  | -+  SVertex* v = &vertices[vertices.size() - 4];
 | 
	
		
			
				|  |  | -   m_color = color;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   unsigned char r = GET_R(color)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index 35e3cf9..4a6a696 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -109,7 +109,7 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   // Stuff for pre-rendering for speed
 | 
	
		
			
				|  |  | -   inline Character *GetCharacter(character_t letter);
 | 
	
		
			
				|  |  | -   bool CacheCharacter(wchar_t letter, uint32_t style, Character *ch);
 | 
	
		
			
				|  |  | --  void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX);
 | 
	
		
			
				|  |  | -+  void RenderCharacter(float posX, float posY, const Character *ch, color_t color, bool roundX, std::vector<SVertex> &vertices);
 | 
	
		
			
				|  |  | -   void ClearCharacterCache();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   virtual CBaseTexture* ReallocTexture(unsigned int& newHeight) = 0;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 79263f02e56ef10410984c98a844aaa9bf43199e Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 15 Jan 2014 17:18:38 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 22/94] Add a cache of font glyph bounding box vertices. This
 | 
	
		
			
				|  |  | - is implemented as a template because ultimately we will key on different
 | 
	
		
			
				|  |  | - parameters and store values of different types, depending upon whether we
 | 
	
		
			
				|  |  | - have a GLES or non-GLES backend, and for GLES, whether or not the currently
 | 
	
		
			
				|  |  | - applicable transformation matrices permit the use of hardware clipping.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontCache.cpp  | 105 ++++++++++++++++++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontCache.h    | 217 ++++++++++++++++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp    | 181 +++++++++++++++++++----------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h      |   5 +
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp  |   1 +
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.h  |   1 +
 | 
	
		
			
				|  |  | - xbmc/guilib/Makefile.in       |   1 +
 | 
	
		
			
				|  |  | - xbmc/guilib/TransformMatrix.h |  11 +++
 | 
	
		
			
				|  |  | - 8 files changed, 438 insertions(+), 84 deletions(-)
 | 
	
		
			
				|  |  | - create mode 100644 xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | - create mode 100644 xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..c029713
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -@@ -0,0 +1,105 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ *      Copyright (C) 2005-2013 Team XBMC
 | 
	
		
			
				|  |  | -+ *      http://xbmc.org
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -+ *  any later version.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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 XBMC; see the file COPYING.  If not, see
 | 
	
		
			
				|  |  | -+ *  <http://www.gnu.org/licenses/>.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include <stdint.h>
 | 
	
		
			
				|  |  | -+#include <vector>
 | 
	
		
			
				|  |  | -+#include "utils/StdString.h" // required by GUIFontTTF.h
 | 
	
		
			
				|  |  | -+#include "GUIFontTTF.h"
 | 
	
		
			
				|  |  | -+#include "GraphicContext.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position, class Value>
 | 
	
		
			
				|  |  | -+void CGUIFontCacheEntry<Position, Value>::Reassign::operator()(CGUIFontCacheEntry<Position, Value> &entry)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  entry.m_key.m_pos = m_key.m_pos;
 | 
	
		
			
				|  |  | -+  entry.m_key.m_colors.assign(m_key.m_colors.begin(), m_key.m_colors.end());
 | 
	
		
			
				|  |  | -+  entry.m_key.m_text.assign(m_key.m_text.begin(), m_key.m_text.end());
 | 
	
		
			
				|  |  | -+  entry.m_key.m_alignment = m_key.m_alignment;
 | 
	
		
			
				|  |  | -+  entry.m_key.m_maxPixelWidth = m_key.m_maxPixelWidth;
 | 
	
		
			
				|  |  | -+  entry.m_key.m_scrolling = m_key.m_scrolling;
 | 
	
		
			
				|  |  | -+  entry.m_matrix = m_key.m_matrix;
 | 
	
		
			
				|  |  | -+  entry.m_key.m_scaleX = m_key.m_scaleX;
 | 
	
		
			
				|  |  | -+  entry.m_key.m_scaleY = m_key.m_scaleY;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  entry.m_lastUsedMillis = m_nowMillis;
 | 
	
		
			
				|  |  | -+  entry.m_value.clear();
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position, class Value>
 | 
	
		
			
				|  |  | -+CGUIFontCacheEntry<Position, Value>::~CGUIFontCacheEntry()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  delete &m_key.m_colors;
 | 
	
		
			
				|  |  | -+  delete &m_key.m_text;
 | 
	
		
			
				|  |  | -+  m_value.clear();
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position, class Value>
 | 
	
		
			
				|  |  | -+Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
 | 
	
		
			
				|  |  | -+                                              const vecColors &colors, const vecText &text,
 | 
	
		
			
				|  |  | -+                                              uint32_t alignment, float maxPixelWidth,
 | 
	
		
			
				|  |  | -+                                              bool scrolling,
 | 
	
		
			
				|  |  | -+                                              unsigned int nowMillis, bool &dirtyCache)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  const CGUIFontCacheKey<Position> key(pos,
 | 
	
		
			
				|  |  | -+                                       const_cast<vecColors &>(colors), const_cast<vecText &>(text),
 | 
	
		
			
				|  |  | -+                                       alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | -+                                       scrolling, g_graphicsContext.GetGUIMatrix(),
 | 
	
		
			
				|  |  | -+                                       g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY());
 | 
	
		
			
				|  |  | -+  EntryHashIterator i = m_list.get<Hash>().find(key);
 | 
	
		
			
				|  |  | -+  if (i == m_list.get<Hash>().end())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    /* Cache miss */
 | 
	
		
			
				|  |  | -+    EntryAgeIterator oldest = m_list.get<Age>().begin();
 | 
	
		
			
				|  |  | -+    if (!m_list.get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      /* The oldest existing entry is old enough to expire and reuse */
 | 
	
		
			
				|  |  | -+      m_list.get<Hash>().modify(m_list.project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
 | 
	
		
			
				|  |  | -+      m_list.get<Age>().relocate(m_list.get<Age>().end(), oldest);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      /* We need a new entry instead */
 | 
	
		
			
				|  |  | -+      /* Yes, this causes the creation an destruction of a temporary entry, but
 | 
	
		
			
				|  |  | -+       * this code ought to only be used infrequently, when the cache needs to grow */
 | 
	
		
			
				|  |  | -+      m_list.get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    dirtyCache = true;
 | 
	
		
			
				|  |  | -+    return (--m_list.get<Age>().end())->m_value;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    /* Cache hit */
 | 
	
		
			
				|  |  | -+    /* Update time in entry and move to the back of the list */
 | 
	
		
			
				|  |  | -+    i->m_lastUsedMillis = nowMillis;
 | 
	
		
			
				|  |  | -+    m_list.get<Age>().relocate(m_list.get<Age>().end(), m_list.project<Age>(i));
 | 
	
		
			
				|  |  | -+    dirtyCache = false;
 | 
	
		
			
				|  |  | -+    return i->m_value;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position, class Value>
 | 
	
		
			
				|  |  | -+void CGUIFontCache<Position, Value>::Flush()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  m_list.get<Age>().clear();
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> &entry);
 | 
	
		
			
				|  |  | -+template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
 | 
	
		
			
				|  |  | -+template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
 | 
	
		
			
				|  |  | -+template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..ef65845
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -@@ -0,0 +1,217 @@
 | 
	
		
			
				|  |  | -+/*!
 | 
	
		
			
				|  |  | -+\file GUIFontCache.h
 | 
	
		
			
				|  |  | -+\brief
 | 
	
		
			
				|  |  | -+*/
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#ifndef CGUILIB_GUIFONTCACHE_H
 | 
	
		
			
				|  |  | -+#define CGUILIB_GUIFONTCACHE_H
 | 
	
		
			
				|  |  | -+#pragma once
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ *      Copyright (C) 2005-2013 Team XBMC
 | 
	
		
			
				|  |  | -+ *      http://xbmc.org
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -+ *  any later version.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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 XBMC; see the file COPYING.  If not, see
 | 
	
		
			
				|  |  | -+ *  <http://www.gnu.org/licenses/>.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include <cstddef>
 | 
	
		
			
				|  |  | -+#include <cstring>
 | 
	
		
			
				|  |  | -+#include <stdint.h>
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include <algorithm>
 | 
	
		
			
				|  |  | -+#include <vector>
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "boost/multi_index_container.hpp"
 | 
	
		
			
				|  |  | -+#include "boost/multi_index/sequenced_index.hpp"
 | 
	
		
			
				|  |  | -+#include "boost/multi_index/hashed_index.hpp"
 | 
	
		
			
				|  |  | -+#include "boost/multi_index/member.hpp"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "TransformMatrix.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+using namespace boost::multi_index;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define FONT_CACHE_TIME_LIMIT (1000)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position, class Value> class CGUIFontCache;
 | 
	
		
			
				|  |  | -+class CGUIFontTTFBase;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position>
 | 
	
		
			
				|  |  | -+struct CGUIFontCacheKey
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  Position m_pos;
 | 
	
		
			
				|  |  | -+  vecColors &m_colors;
 | 
	
		
			
				|  |  | -+  vecText &m_text;
 | 
	
		
			
				|  |  | -+  uint32_t m_alignment;
 | 
	
		
			
				|  |  | -+  float m_maxPixelWidth;
 | 
	
		
			
				|  |  | -+  bool m_scrolling;
 | 
	
		
			
				|  |  | -+  const TransformMatrix &m_matrix;
 | 
	
		
			
				|  |  | -+  float m_scaleX;
 | 
	
		
			
				|  |  | -+  float m_scaleY;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CGUIFontCacheKey(Position pos,
 | 
	
		
			
				|  |  | -+                   vecColors &colors, vecText &text,
 | 
	
		
			
				|  |  | -+                   uint32_t alignment, float maxPixelWidth,
 | 
	
		
			
				|  |  | -+                   bool scrolling, const TransformMatrix &matrix,
 | 
	
		
			
				|  |  | -+                   float scaleX, float scaleY) :
 | 
	
		
			
				|  |  | -+    m_pos(pos),
 | 
	
		
			
				|  |  | -+    m_colors(colors), m_text(text),
 | 
	
		
			
				|  |  | -+    m_alignment(alignment), m_maxPixelWidth(maxPixelWidth),
 | 
	
		
			
				|  |  | -+    m_scrolling(scrolling), m_matrix(matrix),
 | 
	
		
			
				|  |  | -+    m_scaleX(scaleX), m_scaleY(scaleY)
 | 
	
		
			
				|  |  | -+  {}
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position, class Value>
 | 
	
		
			
				|  |  | -+struct CGUIFontCacheEntry
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  const CGUIFontCache<Position, Value> &m_cache;
 | 
	
		
			
				|  |  | -+  CGUIFontCacheKey<Position> m_key;
 | 
	
		
			
				|  |  | -+  TransformMatrix m_matrix;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  /* These need to be declared as mutable to get round the fact that only
 | 
	
		
			
				|  |  | -+   * const iterators are available. These fields do not affect comparison or
 | 
	
		
			
				|  |  | -+   * hash functors, so from the container's point of view, they are mutable. */
 | 
	
		
			
				|  |  | -+  mutable unsigned int m_lastUsedMillis;
 | 
	
		
			
				|  |  | -+  mutable Value m_value;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CGUIFontCacheEntry(const CGUIFontCache<Position, Value> &cache, const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) :
 | 
	
		
			
				|  |  | -+    m_cache(cache),
 | 
	
		
			
				|  |  | -+    m_key(key.m_pos,
 | 
	
		
			
				|  |  | -+          *new vecColors, *new vecText,
 | 
	
		
			
				|  |  | -+          key.m_alignment, key.m_maxPixelWidth,
 | 
	
		
			
				|  |  | -+          key.m_scrolling, m_matrix,
 | 
	
		
			
				|  |  | -+          key.m_scaleX, key.m_scaleY),
 | 
	
		
			
				|  |  | -+    m_lastUsedMillis(nowMillis)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_key.m_colors.assign(key.m_colors.begin(), key.m_colors.end());
 | 
	
		
			
				|  |  | -+    m_key.m_text.assign(key.m_text.begin(), key.m_text.end());
 | 
	
		
			
				|  |  | -+    m_matrix = key.m_matrix;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CGUIFontCacheEntry(const CGUIFontCacheEntry &other) :
 | 
	
		
			
				|  |  | -+    m_cache(other.m_cache),
 | 
	
		
			
				|  |  | -+    m_key(other.m_key.m_pos,
 | 
	
		
			
				|  |  | -+          *new vecColors, *new vecText,
 | 
	
		
			
				|  |  | -+          other.m_key.m_alignment, other.m_key.m_maxPixelWidth,
 | 
	
		
			
				|  |  | -+          other.m_key.m_scrolling, m_matrix,
 | 
	
		
			
				|  |  | -+          other.m_key.m_scaleX, other.m_key.m_scaleY),
 | 
	
		
			
				|  |  | -+    m_lastUsedMillis(other.m_lastUsedMillis),
 | 
	
		
			
				|  |  | -+    m_value(other.m_value)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_key.m_colors.assign(other.m_key.m_colors.begin(), other.m_key.m_colors.end());
 | 
	
		
			
				|  |  | -+    m_key.m_text.assign(other.m_key.m_text.begin(), other.m_key.m_text.end());
 | 
	
		
			
				|  |  | -+    m_matrix = other.m_key.m_matrix;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  struct Reassign
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    Reassign(const CGUIFontCacheKey<Position> &key, unsigned int nowMillis) : m_key(key), m_nowMillis(nowMillis) {}
 | 
	
		
			
				|  |  | -+    void operator()(CGUIFontCacheEntry &entry);
 | 
	
		
			
				|  |  | -+  private:
 | 
	
		
			
				|  |  | -+    const CGUIFontCacheKey<Position> &m_key;
 | 
	
		
			
				|  |  | -+    unsigned int m_nowMillis;
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  ~CGUIFontCacheEntry();
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position>
 | 
	
		
			
				|  |  | -+struct CGUIFontCacheHash
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  size_t operator()(const CGUIFontCacheKey<Position> &key) const
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    /* Not much effort has gone into choosing this hash function */
 | 
	
		
			
				|  |  | -+    size_t hash = 0, i;
 | 
	
		
			
				|  |  | -+    for (i = 0; i < 3 && i < key.m_text.size(); ++i)
 | 
	
		
			
				|  |  | -+      hash += key.m_text[i];
 | 
	
		
			
				|  |  | -+    if (key.m_colors.size())
 | 
	
		
			
				|  |  | -+      hash += key.m_colors[0];
 | 
	
		
			
				|  |  | -+    hash += MatrixHashContribution(key);
 | 
	
		
			
				|  |  | -+    return hash;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position>
 | 
	
		
			
				|  |  | -+struct CGUIFontCacheKeysMatch
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  bool operator()(const CGUIFontCacheKey<Position> &a, const CGUIFontCacheKey<Position> &b) const
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return a.m_text == b.m_text &&
 | 
	
		
			
				|  |  | -+           a.m_colors == b.m_colors &&
 | 
	
		
			
				|  |  | -+           a.m_alignment == b.m_alignment &&
 | 
	
		
			
				|  |  | -+           a.m_scrolling == b.m_scrolling &&
 | 
	
		
			
				|  |  | -+           a.m_maxPixelWidth == b.m_maxPixelWidth &&
 | 
	
		
			
				|  |  | -+           Match(a.m_pos, a.m_matrix, b.m_pos, b.m_matrix, a.m_scrolling) &&
 | 
	
		
			
				|  |  | -+           a.m_scaleX == b.m_scaleX &&
 | 
	
		
			
				|  |  | -+           a.m_scaleY == b.m_scaleY;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template<class Position, class Value>
 | 
	
		
			
				|  |  | -+class CGUIFontCache
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  /* Empty structs used as tags to identify indexes */
 | 
	
		
			
				|  |  | -+  struct Age {};
 | 
	
		
			
				|  |  | -+  struct Hash {};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  typedef multi_index_container<
 | 
	
		
			
				|  |  | -+      CGUIFontCacheEntry<Position, Value>,
 | 
	
		
			
				|  |  | -+      indexed_by<
 | 
	
		
			
				|  |  | -+          sequenced<tag<Age> >,
 | 
	
		
			
				|  |  | -+          hashed_unique<tag<Hash>, member<CGUIFontCacheEntry<Position, Value>, CGUIFontCacheKey<Position>, &CGUIFontCacheEntry<Position, Value>::m_key>, CGUIFontCacheHash<Position>, CGUIFontCacheKeysMatch<Position> >
 | 
	
		
			
				|  |  | -+      >
 | 
	
		
			
				|  |  | -+  > EntryList;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  typedef typename EntryList::template index<Age>::type::iterator EntryAgeIterator;
 | 
	
		
			
				|  |  | -+  typedef typename EntryList::template index<Hash>::type::iterator EntryHashIterator;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  EntryList m_list;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+public:
 | 
	
		
			
				|  |  | -+  const CGUIFontTTFBase &m_font;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CGUIFontCache(CGUIFontTTFBase &font) : m_font(font) {}
 | 
	
		
			
				|  |  | -+  Value &Lookup(Position &pos,
 | 
	
		
			
				|  |  | -+                const vecColors &colors, const vecText &text,
 | 
	
		
			
				|  |  | -+                uint32_t alignment, float maxPixelWidth,
 | 
	
		
			
				|  |  | -+                bool scrolling,
 | 
	
		
			
				|  |  | -+                unsigned int nowMillis, bool &dirtyCache);
 | 
	
		
			
				|  |  | -+  void Flush();
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+struct CGUIFontCacheStaticPosition
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  float m_x;
 | 
	
		
			
				|  |  | -+  float m_y;
 | 
	
		
			
				|  |  | -+  CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+typedef std::vector<SVertex> CGUIFontCacheStaticValue;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+inline bool Match(const CGUIFontCacheStaticPosition &a, const TransformMatrix &a_m,
 | 
	
		
			
				|  |  | -+                  const CGUIFontCacheStaticPosition &b, const TransformMatrix &b_m,
 | 
	
		
			
				|  |  | -+                  bool scrolling)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return a.m_x == b.m_x && a.m_y == b.m_y && a_m == b_m;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPosition> &a)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  /* Ensure horizontally translated versions end up in different buckets */
 | 
	
		
			
				|  |  | -+  return a.m_matrix.m[0][3];
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 1aaf68b..288e61a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -27,6 +27,7 @@
 | 
	
		
			
				|  |  | - #include "utils/MathUtils.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - #include "windowing/WindowingFactory.h"
 | 
	
		
			
				|  |  | -+#include "threads/SystemClock.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include <math.h>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -131,7 +132,7 @@ class CFreeTypeLibrary
 | 
	
		
			
				|  |  | - XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library
 | 
	
		
			
				|  |  | - #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName)
 | 
	
		
			
				|  |  | -+CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_texture = NULL;
 | 
	
		
			
				|  |  | -   m_char = NULL;
 | 
	
		
			
				|  |  | -@@ -330,108 +331,120 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   Begin();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  std::vector<SVertex> &vertices = m_vertex;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // save the origin, which is scaled separately
 | 
	
		
			
				|  |  | --  m_originX = x;
 | 
	
		
			
				|  |  | --  m_originY = y;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // Check if we will really need to truncate or justify the text
 | 
	
		
			
				|  |  | --  if ( alignment & XBFONT_TRUNCATED )
 | 
	
		
			
				|  |  | -+  bool dirtyCache;
 | 
	
		
			
				|  |  | -+  CGUIFontCacheStaticPosition staticPos(x, y);
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> &vertices = m_staticCache.Lookup(staticPos,
 | 
	
		
			
				|  |  | -+                                                        colors, text,
 | 
	
		
			
				|  |  | -+                                                        alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | -+                                                        scrolling,
 | 
	
		
			
				|  |  | -+                                                        XbmcThreads::SystemClockMillis(),
 | 
	
		
			
				|  |  | -+                                                        dirtyCache);
 | 
	
		
			
				|  |  | -+  if (dirtyCache)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
 | 
	
		
			
				|  |  | --      alignment &= ~XBFONT_TRUNCATED;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else if ( alignment & XBFONT_JUSTIFIED )
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if ( maxPixelWidth <= 0.0f )
 | 
	
		
			
				|  |  | --      alignment &= ~XBFONT_JUSTIFIED;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    // save the origin, which is scaled separately
 | 
	
		
			
				|  |  | -+    m_originX = x;
 | 
	
		
			
				|  |  | -+    m_originY = y;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // calculate sizing information
 | 
	
		
			
				|  |  | --  float startX = 0;
 | 
	
		
			
				|  |  | --  float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0;  // vertical centering
 | 
	
		
			
				|  |  | -+    // Check if we will really need to truncate or justify the text
 | 
	
		
			
				|  |  | -+    if ( alignment & XBFONT_TRUNCATED )
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      if ( maxPixelWidth <= 0.0f || GetTextWidthInternal(text.begin(), text.end()) <= maxPixelWidth)
 | 
	
		
			
				|  |  | -+        alignment &= ~XBFONT_TRUNCATED;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if ( alignment & XBFONT_JUSTIFIED )
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      if ( maxPixelWidth <= 0.0f )
 | 
	
		
			
				|  |  | -+        alignment &= ~XBFONT_JUSTIFIED;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    // Get the extent of this line
 | 
	
		
			
				|  |  | --    float w = GetTextWidthInternal( text.begin(), text.end() );
 | 
	
		
			
				|  |  | -+    // calculate sizing information
 | 
	
		
			
				|  |  | -+    float startX = 0;
 | 
	
		
			
				|  |  | -+    float startY = (alignment & XBFONT_CENTER_Y) ? -0.5f*m_cellHeight : 0;  // vertical centering
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
 | 
	
		
			
				|  |  | --      w = maxPixelWidth;
 | 
	
		
			
				|  |  | -+    if ( alignment & (XBFONT_RIGHT | XBFONT_CENTER_X) )
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      // Get the extent of this line
 | 
	
		
			
				|  |  | -+      float w = GetTextWidthInternal( text.begin(), text.end() );
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    if ( alignment & XBFONT_CENTER_X)
 | 
	
		
			
				|  |  | --      w *= 0.5f;
 | 
	
		
			
				|  |  | --    // Offset this line's starting position
 | 
	
		
			
				|  |  | --    startX -= w;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+      if ( alignment & XBFONT_TRUNCATED && w > maxPixelWidth + 0.5f ) // + 0.5f due to rounding issues
 | 
	
		
			
				|  |  | -+        w = maxPixelWidth;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  float spacePerLetter = 0; // for justification effects
 | 
	
		
			
				|  |  | --  if ( alignment & XBFONT_JUSTIFIED )
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    // first compute the size of the text to render in both characters and pixels
 | 
	
		
			
				|  |  | --    unsigned int lineChars = 0;
 | 
	
		
			
				|  |  | --    float linePixels = 0;
 | 
	
		
			
				|  |  | --    for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
 | 
	
		
			
				|  |  | -+      if ( alignment & XBFONT_CENTER_X)
 | 
	
		
			
				|  |  | -+        w *= 0.5f;
 | 
	
		
			
				|  |  | -+      // Offset this line's starting position
 | 
	
		
			
				|  |  | -+      startX -= w;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    float spacePerLetter = 0; // for justification effects
 | 
	
		
			
				|  |  | -+    if ( alignment & XBFONT_JUSTIFIED )
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      Character *ch = GetCharacter(*pos);
 | 
	
		
			
				|  |  | --      if (ch)
 | 
	
		
			
				|  |  | --      { // spaces have multiple times the justification spacing of normal letters
 | 
	
		
			
				|  |  | --        lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
 | 
	
		
			
				|  |  | --        linePixels += ch->advance;
 | 
	
		
			
				|  |  | -+      // first compute the size of the text to render in both characters and pixels
 | 
	
		
			
				|  |  | -+      unsigned int lineChars = 0;
 | 
	
		
			
				|  |  | -+      float linePixels = 0;
 | 
	
		
			
				|  |  | -+      for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        Character *ch = GetCharacter(*pos);
 | 
	
		
			
				|  |  | -+        if (ch)
 | 
	
		
			
				|  |  | -+        { // spaces have multiple times the justification spacing of normal letters
 | 
	
		
			
				|  |  | -+          lineChars += ((*pos & 0xffff) == L' ') ? justification_word_weight : 1;
 | 
	
		
			
				|  |  | -+          linePixels += ch->advance;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -+      if (lineChars > 1)
 | 
	
		
			
				|  |  | -+        spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    if (lineChars > 1)
 | 
	
		
			
				|  |  | --      spacePerLetter = (maxPixelWidth - linePixels) / (lineChars - 1);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  float cursorX = 0; // current position along the line
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    // If starting text on a new line, determine justification effects
 | 
	
		
			
				|  |  | --    // Get the current letter in the CStdString
 | 
	
		
			
				|  |  | --    color_t color = (*pos & 0xff0000) >> 16;
 | 
	
		
			
				|  |  | --    if (color >= colors.size())
 | 
	
		
			
				|  |  | --      color = 0;
 | 
	
		
			
				|  |  | --    color = colors[color];
 | 
	
		
			
				|  |  | -+    float cursorX = 0; // current position along the line
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    // grab the next character
 | 
	
		
			
				|  |  | --    Character *ch = GetCharacter(*pos);
 | 
	
		
			
				|  |  | --    if (!ch) continue;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if ( alignment & XBFONT_TRUNCATED )
 | 
	
		
			
				|  |  | -+    for (vecText::const_iterator pos = text.begin(); pos != text.end(); ++pos)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      // Check if we will be exceeded the max allowed width
 | 
	
		
			
				|  |  | --      if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        // Yup. Let's draw the ellipses, then bail
 | 
	
		
			
				|  |  | --        // Perhaps we should really bail to the next line in this case??
 | 
	
		
			
				|  |  | --        Character *period = GetCharacter(L'.');
 | 
	
		
			
				|  |  | --        if (!period)
 | 
	
		
			
				|  |  | --          break;
 | 
	
		
			
				|  |  | -+      // If starting text on a new line, determine justification effects
 | 
	
		
			
				|  |  | -+      // Get the current letter in the CStdString
 | 
	
		
			
				|  |  | -+      color_t color = (*pos & 0xff0000) >> 16;
 | 
	
		
			
				|  |  | -+      if (color >= colors.size())
 | 
	
		
			
				|  |  | -+        color = 0;
 | 
	
		
			
				|  |  | -+      color = colors[color];
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      // grab the next character
 | 
	
		
			
				|  |  | -+      Character *ch = GetCharacter(*pos);
 | 
	
		
			
				|  |  | -+      if (!ch) continue;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --        for (int i = 0; i < 3; i++)
 | 
	
		
			
				|  |  | -+      if ( alignment & XBFONT_TRUNCATED )
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        // Check if we will be exceeded the max allowed width
 | 
	
		
			
				|  |  | -+        if ( cursorX + ch->advance + 3 * m_ellipsesWidth > maxPixelWidth )
 | 
	
		
			
				|  |  | -         {
 | 
	
		
			
				|  |  | --          RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
 | 
	
		
			
				|  |  | --          cursorX += period->advance;
 | 
	
		
			
				|  |  | -+          // Yup. Let's draw the ellipses, then bail
 | 
	
		
			
				|  |  | -+          // Perhaps we should really bail to the next line in this case??
 | 
	
		
			
				|  |  | -+          Character *period = GetCharacter(L'.');
 | 
	
		
			
				|  |  | -+          if (!period)
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+          for (int i = 0; i < 3; i++)
 | 
	
		
			
				|  |  | -+          {
 | 
	
		
			
				|  |  | -+            RenderCharacter(startX + cursorX, startY, period, color, !scrolling, vertices);
 | 
	
		
			
				|  |  | -+            cursorX += period->advance;
 | 
	
		
			
				|  |  | -+          }
 | 
	
		
			
				|  |  | -+          break;
 | 
	
		
			
				|  |  | -         }
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
 | 
	
		
			
				|  |  | --      break;  // exceeded max allowed width - stop rendering
 | 
	
		
			
				|  |  | -+      else if (maxPixelWidth > 0 && cursorX > maxPixelWidth)
 | 
	
		
			
				|  |  | -+        break;  // exceeded max allowed width - stop rendering
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
 | 
	
		
			
				|  |  | --    if ( alignment & XBFONT_JUSTIFIED )
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      if ((*pos & 0xffff) == L' ')
 | 
	
		
			
				|  |  | --        cursorX += ch->advance + spacePerLetter * justification_word_weight;
 | 
	
		
			
				|  |  | -+      RenderCharacter(startX + cursorX, startY, ch, color, !scrolling, vertices);
 | 
	
		
			
				|  |  | -+      if ( alignment & XBFONT_JUSTIFIED )
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        if ((*pos & 0xffff) == L' ')
 | 
	
		
			
				|  |  | -+          cursorX += ch->advance + spacePerLetter * justification_word_weight;
 | 
	
		
			
				|  |  | -+        else
 | 
	
		
			
				|  |  | -+          cursorX += ch->advance + spacePerLetter;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -       else
 | 
	
		
			
				|  |  | --        cursorX += ch->advance + spacePerLetter;
 | 
	
		
			
				|  |  | -+        cursorX += ch->advance;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --      cursorX += ch->advance;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  /* Append the new vertices (from the cache or otherwise) to the set collected
 | 
	
		
			
				|  |  | -+   * since the first Begin() call */
 | 
	
		
			
				|  |  | -+  m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   End();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index 4a6a696..7cb4669 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -64,6 +64,9 @@ struct SVertex
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#include "GUIFontCache.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - class CGUIFontTTFBase
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   friend class CGUIFont;
 | 
	
		
			
				|  |  | -@@ -166,6 +169,8 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   CStdString m_strFileName;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> m_staticCache;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -   virtual bool FirstBegin() = 0;
 | 
	
		
			
				|  |  | -   virtual void LastEnd() = 0;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index a4e8571..cb56987 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -200,6 +200,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
 | 
	
		
			
				|  |  | -   m_textureScaleX = 1.0f / m_textureWidth;
 | 
	
		
			
				|  |  | -   if (m_textureHeight < newHeight)
 | 
	
		
			
				|  |  | -     CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
 | 
	
		
			
				|  |  | -+  m_staticCache.Flush();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
 | 
	
		
			
				|  |  | -   if (m_texture)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -index 6c2dcd4..bab2457 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -@@ -146,6 +146,7 @@ class CGraphicContext : public CCriticalSection,
 | 
	
		
			
				|  |  | -   inline void ScaleFinalCoords(float &x, float &y, float &z) const XBMC_FORCE_INLINE { m_finalTransform.matrix.TransformPosition(x, y, z); }
 | 
	
		
			
				|  |  | -   bool RectIsAngled(float x1, float y1, float x2, float y2) const;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  inline const TransformMatrix &GetGUIMatrix() const XBMC_FORCE_INLINE { return m_finalTransform.matrix; }
 | 
	
		
			
				|  |  | -   inline float GetGUIScaleX() const XBMC_FORCE_INLINE { return m_finalTransform.scaleX; }
 | 
	
		
			
				|  |  | -   inline float GetGUIScaleY() const XBMC_FORCE_INLINE { return m_finalTransform.scaleY; }
 | 
	
		
			
				|  |  | -   inline color_t MergeAlpha(color_t color) const XBMC_FORCE_INLINE
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/Makefile.in b/xbmc/guilib/Makefile.in
 | 
	
		
			
				|  |  | -index 086fb0d..af82979 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/Makefile.in
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/Makefile.in
 | 
	
		
			
				|  |  | -@@ -23,6 +23,7 @@ SRCS += GUIEditControl.cpp
 | 
	
		
			
				|  |  | - SRCS += GUIFadeLabelControl.cpp
 | 
	
		
			
				|  |  | - SRCS += GUIFixedListContainer.cpp
 | 
	
		
			
				|  |  | - SRCS += GUIFont.cpp
 | 
	
		
			
				|  |  | -+SRCS += GUIFontCache.cpp
 | 
	
		
			
				|  |  | - SRCS += GUIFontManager.cpp
 | 
	
		
			
				|  |  | - SRCS += GUIFontTTF.cpp
 | 
	
		
			
				|  |  | - SRCS += GUIImage.cpp
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/TransformMatrix.h b/xbmc/guilib/TransformMatrix.h
 | 
	
		
			
				|  |  | -index f351c99..9036ba9 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/TransformMatrix.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/TransformMatrix.h
 | 
	
		
			
				|  |  | -@@ -245,3 +245,14 @@ class TransformMatrix
 | 
	
		
			
				|  |  | -   float alpha;
 | 
	
		
			
				|  |  | -   bool identity;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+inline bool operator==(const TransformMatrix &a, const TransformMatrix &b)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return a.alpha == b.alpha && ((a.identity && b.identity) ||
 | 
	
		
			
				|  |  | -+      (!a.identity && !b.identity && std::equal(&a.m[0][0], &a.m[0][0] + sizeof a.m / sizeof a.m[0][0], &b.m[0][0])));
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+inline bool operator!=(const TransformMatrix &a, const TransformMatrix &b)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return !operator==(a, b);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 65d2b7f112b400f75140de44579e6cdf98378b67 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Thu, 23 Jan 2014 22:24:17 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 23/94] Lay the groundwork for hardware clipping.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -For glScissor() to replace CGraphicContext::ClipRect, a necessary condition
 | 
	
		
			
				|  |  | -is that no shear or rotation is introduced between the coordinate systems
 | 
	
		
			
				|  |  | -they use; this depends upon the settings of the GUI matrix m_finalTransform
 | 
	
		
			
				|  |  | -as well as the OpenGL model-view and projection matrices. These all remain
 | 
	
		
			
				|  |  | -unchanged between paired calls of CGUIShader::OnEnabled and
 | 
	
		
			
				|  |  | -CGUIShader::OnDisabled, so we scan the matrices in CGUIShader::OnEnabled to
 | 
	
		
			
				|  |  | -see whether hardware clipping is possible.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Then, in CGUIFontTTFBase::RenderCharacter, we don't apply software clipping
 | 
	
		
			
				|  |  | -in such cases. However, because vertices arising from multiple
 | 
	
		
			
				|  |  | -CGUIFontTTFBase::DrawTextInternal calls (each of which often uses a different
 | 
	
		
			
				|  |  | -clip rectangle) get lumped into the same vector, which only at the end is
 | 
	
		
			
				|  |  | -passed to OpenGL for rendering, we need to wait a few commits before we can
 | 
	
		
			
				|  |  | -actually apply hardware clipping. In the meantime, expect to see rendering
 | 
	
		
			
				|  |  | -errors.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp               |  3 +-
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIShader.cpp                | 80 +++++++++++++++++++++++++++++++-
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIShader.h                  | 11 +++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.cpp           | 10 ++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.h             |  1 +
 | 
	
		
			
				|  |  | - xbmc/rendering/RenderSystem.h            |  2 +
 | 
	
		
			
				|  |  | - xbmc/rendering/gles/RenderSystemGLES.cpp | 22 +++++++++
 | 
	
		
			
				|  |  | - xbmc/rendering/gles/RenderSystemGLES.h   |  2 +
 | 
	
		
			
				|  |  | - 8 files changed, 128 insertions(+), 3 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 288e61a..19c7ff4 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -710,7 +710,8 @@ void CGUIFontTTFBase::RenderCharacter(float posX, float posY, const Character *c
 | 
	
		
			
				|  |  | -                (posY + ch->offsetY + height) * g_graphicsContext.GetGUIScaleY());
 | 
	
		
			
				|  |  | -   vertex += CPoint(m_originX, m_originY);
 | 
	
		
			
				|  |  | -   CRect texture(ch->left, ch->top, ch->right, ch->bottom);
 | 
	
		
			
				|  |  | --  g_graphicsContext.ClipRect(vertex, texture);
 | 
	
		
			
				|  |  | -+  if (!g_Windowing.ScissorsCanEffectClipping())
 | 
	
		
			
				|  |  | -+    g_graphicsContext.ClipRect(vertex, texture);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // transform our positions - note, no scaling due to GUI calibration/resolution occurs
 | 
	
		
			
				|  |  | -   float x[4], y[4], z[4];
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp
 | 
	
		
			
				|  |  | -index 11089b8..53bce09 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIShader.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIShader.cpp
 | 
	
		
			
				|  |  | -@@ -26,6 +26,8 @@
 | 
	
		
			
				|  |  | - #include "GUIShader.h"
 | 
	
		
			
				|  |  | - #include "MatrixGLES.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | -+#include "windowing/egl/WinSystemEGL.h"
 | 
	
		
			
				|  |  | -+#include "guilib/GraphicContext.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - CGUIShader::CGUIShader( const char *shader ) : CGLSLShaderProgram("guishader_vert.glsl", shader)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -@@ -86,8 +88,82 @@ bool CGUIShader::OnEnabled()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   // This is called after glUseProgram()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  glUniformMatrix4fv(m_hProj,  1, GL_FALSE, g_matrices.GetMatrix(MM_PROJECTION));
 | 
	
		
			
				|  |  | --  glUniformMatrix4fv(m_hModel, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | -+  GLfloat *projMatrix = g_matrices.GetMatrix(MM_PROJECTION);
 | 
	
		
			
				|  |  | -+  GLfloat *modelMatrix = g_matrices.GetMatrix(MM_MODELVIEW);
 | 
	
		
			
				|  |  | -+  glUniformMatrix4fv(m_hProj,  1, GL_FALSE, projMatrix);
 | 
	
		
			
				|  |  | -+  glUniformMatrix4fv(m_hModel, 1, GL_FALSE, modelMatrix);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  const TransformMatrix &guiMatrix = g_graphicsContext.GetGUIMatrix();
 | 
	
		
			
				|  |  | -+  CRect viewPort; // absolute positions of corners
 | 
	
		
			
				|  |  | -+  g_Windowing.GetViewPort(viewPort);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  /* glScissor operates in window coordinates. In order that we can use it to
 | 
	
		
			
				|  |  | -+   * perform clipping, we must ensure that there is an independent linear
 | 
	
		
			
				|  |  | -+   * transformation from the coordinate system used by CGraphicContext::ClipRect
 | 
	
		
			
				|  |  | -+   * to window coordinates, separately for X and Y (in other words, no
 | 
	
		
			
				|  |  | -+   * rotation or shear is introduced at any stage). To do, this, we need to
 | 
	
		
			
				|  |  | -+   * check that zeros are present in the following locations:
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   * GUI matrix:
 | 
	
		
			
				|  |  | -+   * / * 0 * * \
 | 
	
		
			
				|  |  | -+   * | 0 * * * |
 | 
	
		
			
				|  |  | -+   * \ 0 0 * * /
 | 
	
		
			
				|  |  | -+   *       ^ TransformMatrix::TransformX/Y/ZCoord are only ever called with
 | 
	
		
			
				|  |  | -+   *         input z = 0, so this column doesn't matter
 | 
	
		
			
				|  |  | -+   * Model-view matrix:
 | 
	
		
			
				|  |  | -+   * / * 0 0 * \
 | 
	
		
			
				|  |  | -+   * | 0 * 0 * |
 | 
	
		
			
				|  |  | -+   * | 0 0 * * |
 | 
	
		
			
				|  |  | -+   * \ * * * * /  <- eye w has no influence on window x/y (last column below
 | 
	
		
			
				|  |  | -+   *                                                       is either 0 or ignored)
 | 
	
		
			
				|  |  | -+   * Projection matrix:
 | 
	
		
			
				|  |  | -+   * / * 0 0 0 \
 | 
	
		
			
				|  |  | -+   * | 0 * 0 0 |
 | 
	
		
			
				|  |  | -+   * | * * * * |  <- normalised device coordinate z has no influence on window x/y
 | 
	
		
			
				|  |  | -+   * \ 0 0 * 0 /
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   * Some of these zeros are not strictly required to ensure this, but they tend
 | 
	
		
			
				|  |  | -+   * to be zeroed in the common case, so by checking for zeros here, we simplify
 | 
	
		
			
				|  |  | -+   * the calculation of the window x/y coordinates further down the line.
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   * (Minor detail: we don't quite deal in window coordinates as defined by
 | 
	
		
			
				|  |  | -+   * OpenGL, because CRenderSystemGLES::SetScissors flips the Y axis. But all
 | 
	
		
			
				|  |  | -+   * that's needed to handle that is an effective negation at the stage where
 | 
	
		
			
				|  |  | -+   * Y is in normalised device coordinates.)
 | 
	
		
			
				|  |  | -+   */
 | 
	
		
			
				|  |  | -+  m_clipPossible = guiMatrix.m[0][1] == 0 &&
 | 
	
		
			
				|  |  | -+      guiMatrix.m[1][0] == 0 &&
 | 
	
		
			
				|  |  | -+      guiMatrix.m[2][0] == 0 &&
 | 
	
		
			
				|  |  | -+      guiMatrix.m[2][1] == 0 &&
 | 
	
		
			
				|  |  | -+      modelMatrix[0+1*4] == 0 &&
 | 
	
		
			
				|  |  | -+      modelMatrix[0+2*4] == 0 &&
 | 
	
		
			
				|  |  | -+      modelMatrix[1+0*4] == 0 &&
 | 
	
		
			
				|  |  | -+      modelMatrix[1+2*4] == 0 &&
 | 
	
		
			
				|  |  | -+      modelMatrix[2+0*4] == 0 &&
 | 
	
		
			
				|  |  | -+      modelMatrix[2+1*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[0+1*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[0+2*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[0+3*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[1+0*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[1+2*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[1+3*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[3+0*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[3+1*4] == 0 &&
 | 
	
		
			
				|  |  | -+      projMatrix[3+3*4] == 0;
 | 
	
		
			
				|  |  | -+  if (m_clipPossible)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_clipXFactor = guiMatrix.m[0][0] * modelMatrix[0+0*4] * projMatrix[0+0*4];
 | 
	
		
			
				|  |  | -+    m_clipXOffset = (guiMatrix.m[0][3] * modelMatrix[0+0*4] + modelMatrix[0+3*4]) * projMatrix[0+0*4];
 | 
	
		
			
				|  |  | -+    m_clipYFactor = guiMatrix.m[1][1] * modelMatrix[1+1*4] * projMatrix[1+1*4];
 | 
	
		
			
				|  |  | -+    m_clipYOffset = (guiMatrix.m[1][3] * modelMatrix[1+1*4] + modelMatrix[1+3*4]) * projMatrix[1+1*4];
 | 
	
		
			
				|  |  | -+    float clipW = (guiMatrix.m[2][3] * modelMatrix[2+2*4] + modelMatrix[2+3*4]) * projMatrix[3+2*4];
 | 
	
		
			
				|  |  | -+    float xMult = (viewPort.x2 - viewPort.x1) / (2 * clipW);
 | 
	
		
			
				|  |  | -+    float yMult = (viewPort.y1 - viewPort.y2) / (2 * clipW); // correct for inverted window coordinate scheme
 | 
	
		
			
				|  |  | -+    m_clipXFactor = m_clipXFactor * xMult;
 | 
	
		
			
				|  |  | -+    m_clipXOffset = m_clipXOffset * xMult + (viewPort.x2 + viewPort.x1) / 2;
 | 
	
		
			
				|  |  | -+    m_clipYFactor = m_clipYFactor * yMult;
 | 
	
		
			
				|  |  | -+    m_clipYOffset = m_clipYOffset * yMult + (viewPort.y2 + viewPort.y1) / 2;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h
 | 
	
		
			
				|  |  | -index c7e95aa..86ce4cc 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIShader.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIShader.h
 | 
	
		
			
				|  |  | -@@ -41,6 +41,11 @@ class CGUIShader : public CGLSLShaderProgram
 | 
	
		
			
				|  |  | -   GLint GetCord1Loc() { return m_hCord1; }
 | 
	
		
			
				|  |  | -   GLint GetUniColLoc() { return m_hUniCol; }
 | 
	
		
			
				|  |  | -   GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; }
 | 
	
		
			
				|  |  | -+  bool HardwareClipIsPossible() { return m_clipPossible; }
 | 
	
		
			
				|  |  | -+  GLfloat GetClipXFactor() { return m_clipXFactor; }
 | 
	
		
			
				|  |  | -+  GLfloat GetClipXOffset() { return m_clipXOffset; }
 | 
	
		
			
				|  |  | -+  GLfloat GetClipYFactor() { return m_clipYFactor; }
 | 
	
		
			
				|  |  | -+  GLfloat GetClipYOffset() { return m_clipYOffset; }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   GLint m_hTex0;
 | 
	
		
			
				|  |  | -@@ -56,6 +61,12 @@ class CGUIShader : public CGLSLShaderProgram
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   GLfloat *m_proj;
 | 
	
		
			
				|  |  | -   GLfloat *m_model;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  bool m_clipPossible;
 | 
	
		
			
				|  |  | -+  GLfloat m_clipXFactor;
 | 
	
		
			
				|  |  | -+  GLfloat m_clipXOffset;
 | 
	
		
			
				|  |  | -+  GLfloat m_clipYFactor;
 | 
	
		
			
				|  |  | -+  GLfloat m_clipYOffset;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif // GUI_SHADER_H
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -index 38f17a7..5bffdf5 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -@@ -167,6 +167,16 @@ void CGraphicContext::ClipRect(CRect &vertex, CRect &texture, CRect *texture2)
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+CRect CGraphicContext::GetClipRegion()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (m_clipRegions.empty())
 | 
	
		
			
				|  |  | -+    return CRect(0, 0, m_iScreenWidth, m_iScreenHeight);
 | 
	
		
			
				|  |  | -+  CRect clipRegion(m_clipRegions.top());
 | 
	
		
			
				|  |  | -+  if (!m_origins.empty())
 | 
	
		
			
				|  |  | -+    clipRegion -= m_origins.top();
 | 
	
		
			
				|  |  | -+  return clipRegion;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - bool CGraphicContext::SetViewPort(float fx, float fy, float fwidth, float fheight, bool intersectPrevious /* = false */)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   // transform coordinates - we may have a rotation which changes the positioning of the
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -index bab2457..0a27643 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -@@ -199,6 +199,7 @@ class CGraphicContext : public CCriticalSection,
 | 
	
		
			
				|  |  | -   void ApplyHardwareTransform();
 | 
	
		
			
				|  |  | -   void RestoreHardwareTransform();
 | 
	
		
			
				|  |  | -   void ClipRect(CRect &vertex, CRect &texture, CRect *diffuse = NULL);
 | 
	
		
			
				|  |  | -+  CRect GetClipRegion();
 | 
	
		
			
				|  |  | -   inline void AddGUITransform()
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     m_transforms.push(m_finalTransform);
 | 
	
		
			
				|  |  | -diff --git a/xbmc/rendering/RenderSystem.h b/xbmc/rendering/RenderSystem.h
 | 
	
		
			
				|  |  | -index fa64eba..c1dfb93 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/rendering/RenderSystem.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/rendering/RenderSystem.h
 | 
	
		
			
				|  |  | -@@ -110,6 +110,8 @@ class CRenderSystemBase
 | 
	
		
			
				|  |  | -   virtual void GetViewPort(CRect& viewPort) = 0;
 | 
	
		
			
				|  |  | -   virtual void RestoreViewPort() {};
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  virtual bool ScissorsCanEffectClipping() { return false; }
 | 
	
		
			
				|  |  | -+  virtual CRect ClipRectToScissorRect(const CRect &rect) { return CRect(); }
 | 
	
		
			
				|  |  | -   virtual void SetScissors(const CRect &rect) = 0;
 | 
	
		
			
				|  |  | -   virtual void ResetScissors() = 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp
 | 
	
		
			
				|  |  | -index 653c9ec..deb3afc 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/rendering/gles/RenderSystemGLES.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/rendering/gles/RenderSystemGLES.cpp
 | 
	
		
			
				|  |  | -@@ -533,6 +533,28 @@ void CRenderSystemGLES::SetViewPort(CRect& viewPort)
 | 
	
		
			
				|  |  | -   m_viewPort[3] = viewPort.Height();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+bool CRenderSystemGLES::ScissorsCanEffectClipping()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (m_pGUIshader[m_method])
 | 
	
		
			
				|  |  | -+    return m_pGUIshader[m_method]->HardwareClipIsPossible();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return false;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CRect CRenderSystemGLES::ClipRectToScissorRect(const CRect &rect)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (!m_pGUIshader[m_method])
 | 
	
		
			
				|  |  | -+    return CRect();
 | 
	
		
			
				|  |  | -+  float xFactor = m_pGUIshader[m_method]->GetClipXFactor();
 | 
	
		
			
				|  |  | -+  float xOffset = m_pGUIshader[m_method]->GetClipXOffset();
 | 
	
		
			
				|  |  | -+  float yFactor = m_pGUIshader[m_method]->GetClipYFactor();
 | 
	
		
			
				|  |  | -+  float yOffset = m_pGUIshader[m_method]->GetClipYOffset();
 | 
	
		
			
				|  |  | -+  return CRect(rect.x1 * xFactor + xOffset,
 | 
	
		
			
				|  |  | -+               rect.y1 * yFactor + yOffset,
 | 
	
		
			
				|  |  | -+               rect.x2 * xFactor + xOffset,
 | 
	
		
			
				|  |  | -+               rect.y2 * yFactor + yOffset);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - void CRenderSystemGLES::SetScissors(const CRect &rect)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (!m_bRenderCreated)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h
 | 
	
		
			
				|  |  | -index 98e398a..81ee49e 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/rendering/gles/RenderSystemGLES.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/rendering/gles/RenderSystemGLES.h
 | 
	
		
			
				|  |  | -@@ -63,6 +63,8 @@ class CRenderSystemGLES : public CRenderSystemBase
 | 
	
		
			
				|  |  | -   virtual void SetViewPort(CRect& viewPort);
 | 
	
		
			
				|  |  | -   virtual void GetViewPort(CRect& viewPort);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  virtual bool ScissorsCanEffectClipping();
 | 
	
		
			
				|  |  | -+  virtual CRect ClipRectToScissorRect(const CRect &rect);
 | 
	
		
			
				|  |  | -   virtual void SetScissors(const CRect& rect);
 | 
	
		
			
				|  |  | -   virtual void ResetScissors();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From e372121bc53da1b0353b51f5e9897011c5f54033 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Thu, 23 Jan 2014 16:42:22 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 24/94] Increase font cache hit rate by keying on the
 | 
	
		
			
				|  |  | - fractional part of m_originX and m_originY *after* they have been through the
 | 
	
		
			
				|  |  | - graphics context's transformation matrix, plus the scale/rotation elements of
 | 
	
		
			
				|  |  | - the matrix, rather than the origin in the original frame of reference plus
 | 
	
		
			
				|  |  | - the complete transformation matrix. All vertices of individual glyph bounding
 | 
	
		
			
				|  |  | - boxes are a constant offset from this position, and when the fractional part
 | 
	
		
			
				|  |  | - of the translation is a match, the rounding of each vertex will be in the
 | 
	
		
			
				|  |  | - same direction; this permits us to calculate the desired vertices from the
 | 
	
		
			
				|  |  | - cached ones simply by adding the integer parts of the translations with no
 | 
	
		
			
				|  |  | - additional rounding steps.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Note that this requires that software clipping is *not* performed.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontCache.cpp |  8 +++++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontCache.h   | 43 +++++++++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp   | 53 +++++++++++++++++++++++++++++++++++---------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h     |  1 +
 | 
	
		
			
				|  |  | - 4 files changed, 95 insertions(+), 10 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -index c029713..b66c00b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -@@ -85,6 +85,9 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     /* Cache hit */
 | 
	
		
			
				|  |  | -+    /* Update the translation arguments so that they hold the offset to apply
 | 
	
		
			
				|  |  | -+     * to the cached values (but only in the dynamic case) */
 | 
	
		
			
				|  |  | -+    pos.UpdateWithOffsets(i->m_key.m_pos, scrolling);
 | 
	
		
			
				|  |  | -     /* Update time in entry and move to the back of the list */
 | 
	
		
			
				|  |  | -     i->m_lastUsedMillis = nowMillis;
 | 
	
		
			
				|  |  | -     m_list.get<Age>().relocate(m_list.get<Age>().end(), m_list.project<Age>(i));
 | 
	
		
			
				|  |  | -@@ -103,3 +106,8 @@ template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStati
 | 
	
		
			
				|  |  | - template CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::~CGUIFontCacheEntry();
 | 
	
		
			
				|  |  | - template CGUIFontCacheStaticValue &CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Lookup(CGUIFontCacheStaticPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
 | 
	
		
			
				|  |  | - template void CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Flush();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+template void CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue> &entry);
 | 
	
		
			
				|  |  | -+template CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCacheEntry();
 | 
	
		
			
				|  |  | -+template CGUIFontCacheDynamicValue &CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
 | 
	
		
			
				|  |  | -+template void CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Flush();
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -index ef65845..d913dee 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -@@ -44,6 +44,7 @@
 | 
	
		
			
				|  |  | - using namespace boost::multi_index;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define FONT_CACHE_TIME_LIMIT (1000)
 | 
	
		
			
				|  |  | -+#define FONT_CACHE_DIST_LIMIT (0.01)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - template<class Position, class Value> class CGUIFontCache;
 | 
	
		
			
				|  |  | - class CGUIFontTTFBase;
 | 
	
		
			
				|  |  | -@@ -197,6 +198,7 @@ struct CGUIFontCacheStaticPosition
 | 
	
		
			
				|  |  | -   float m_x;
 | 
	
		
			
				|  |  | -   float m_y;
 | 
	
		
			
				|  |  | -   CGUIFontCacheStaticPosition(float x, float y) : m_x(x), m_y(y) {}
 | 
	
		
			
				|  |  | -+  void UpdateWithOffsets(const CGUIFontCacheStaticPosition &cached, bool scrolling) {}
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - typedef std::vector<SVertex> CGUIFontCacheStaticValue;
 | 
	
		
			
				|  |  | -@@ -214,4 +216,45 @@ inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheStaticPo
 | 
	
		
			
				|  |  | -   return a.m_matrix.m[0][3];
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+struct CGUIFontCacheDynamicPosition
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  float m_x;
 | 
	
		
			
				|  |  | -+  float m_y;
 | 
	
		
			
				|  |  | -+  float m_z;
 | 
	
		
			
				|  |  | -+  CGUIFontCacheDynamicPosition() {}
 | 
	
		
			
				|  |  | -+  CGUIFontCacheDynamicPosition(float x, float y, float z) : m_x(x), m_y(y), m_z(z) {}
 | 
	
		
			
				|  |  | -+  void UpdateWithOffsets(const CGUIFontCacheDynamicPosition &cached, bool scrolling)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (scrolling)
 | 
	
		
			
				|  |  | -+      m_x = m_x - cached.m_x;
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+      m_x = floorf(m_x - cached.m_x + FONT_CACHE_DIST_LIMIT);
 | 
	
		
			
				|  |  | -+    m_y = floorf(m_y - cached.m_y + FONT_CACHE_DIST_LIMIT);
 | 
	
		
			
				|  |  | -+    m_z = floorf(m_z - cached.m_z + FONT_CACHE_DIST_LIMIT);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+typedef std::vector<SVertex> CGUIFontCacheDynamicValue;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m,
 | 
	
		
			
				|  |  | -+                  const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m,
 | 
	
		
			
				|  |  | -+                  bool scrolling)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  float diffX = a.m_x - b.m_x + FONT_CACHE_DIST_LIMIT;
 | 
	
		
			
				|  |  | -+  float diffY = a.m_y - b.m_y + FONT_CACHE_DIST_LIMIT;
 | 
	
		
			
				|  |  | -+  float diffZ = a.m_z - b.m_z + FONT_CACHE_DIST_LIMIT;
 | 
	
		
			
				|  |  | -+  return (scrolling || diffX - floorf(diffX) < 2 * FONT_CACHE_DIST_LIMIT) &&
 | 
	
		
			
				|  |  | -+          diffY - floorf(diffY) < 2 * FONT_CACHE_DIST_LIMIT &&
 | 
	
		
			
				|  |  | -+          diffZ - floorf(diffZ) < 2 * FONT_CACHE_DIST_LIMIT &&
 | 
	
		
			
				|  |  | -+          a_m.m[0][0] == b_m.m[0][0] &&
 | 
	
		
			
				|  |  | -+          a_m.m[1][1] == b_m.m[1][1] &&
 | 
	
		
			
				|  |  | -+          a_m.m[2][2] == b_m.m[2][2];
 | 
	
		
			
				|  |  | -+          // We already know the first 3 columns of both matrices are diagonal, so no need to check the other elements
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+inline float MatrixHashContribution(const CGUIFontCacheKey<CGUIFontCacheDynamicPosition> &a)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return 0;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 19c7ff4..73f0e50 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -132,7 +132,7 @@ class CFreeTypeLibrary
 | 
	
		
			
				|  |  | - XBMC_GLOBAL_REF(CFreeTypeLibrary, g_freeTypeLibrary); // our freetype library
 | 
	
		
			
				|  |  | - #define g_freeTypeLibrary XBMC_GLOBAL_USE(CFreeTypeLibrary)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this)
 | 
	
		
			
				|  |  | -+CGUIFontTTFBase::CGUIFontTTFBase(const CStdString& strFileName) : m_staticCache(*this), m_dynamicCache(*this)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_texture = NULL;
 | 
	
		
			
				|  |  | -   m_char = NULL;
 | 
	
		
			
				|  |  | -@@ -332,13 +332,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | -   Begin();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool dirtyCache;
 | 
	
		
			
				|  |  | -+  bool hardwareClipping = g_Windowing.ScissorsCanEffectClipping();
 | 
	
		
			
				|  |  | -   CGUIFontCacheStaticPosition staticPos(x, y);
 | 
	
		
			
				|  |  | --  std::vector<SVertex> &vertices = m_staticCache.Lookup(staticPos,
 | 
	
		
			
				|  |  | --                                                        colors, text,
 | 
	
		
			
				|  |  | --                                                        alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | --                                                        scrolling,
 | 
	
		
			
				|  |  | --                                                        XbmcThreads::SystemClockMillis(),
 | 
	
		
			
				|  |  | --                                                        dirtyCache);
 | 
	
		
			
				|  |  | -+  CGUIFontCacheDynamicPosition dynamicPos;
 | 
	
		
			
				|  |  | -+  if (hardwareClipping)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    dynamicPos = CGUIFontCacheDynamicPosition(g_graphicsContext.ScaleFinalXCoord(x, y),
 | 
	
		
			
				|  |  | -+                                              g_graphicsContext.ScaleFinalYCoord(x, y),
 | 
	
		
			
				|  |  | -+                                              g_graphicsContext.ScaleFinalZCoord(x, y));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> &vertices = hardwareClipping ?
 | 
	
		
			
				|  |  | -+      m_dynamicCache.Lookup(dynamicPos,
 | 
	
		
			
				|  |  | -+                            colors, text,
 | 
	
		
			
				|  |  | -+                            alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | -+                            scrolling,
 | 
	
		
			
				|  |  | -+                            XbmcThreads::SystemClockMillis(),
 | 
	
		
			
				|  |  | -+                            dirtyCache) :
 | 
	
		
			
				|  |  | -+      m_staticCache.Lookup(staticPos,
 | 
	
		
			
				|  |  | -+                           colors, text,
 | 
	
		
			
				|  |  | -+                           alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | -+                           scrolling,
 | 
	
		
			
				|  |  | -+                           XbmcThreads::SystemClockMillis(),
 | 
	
		
			
				|  |  | -+                           dirtyCache);
 | 
	
		
			
				|  |  | -   if (dirtyCache)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     // save the origin, which is scaled separately
 | 
	
		
			
				|  |  | -@@ -441,10 +456,28 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | -       else
 | 
	
		
			
				|  |  | -         cursorX += ch->advance;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+    if (hardwareClipping)
 | 
	
		
			
				|  |  | -+      /* Append the new vertices (which we have just constructed in the cache)
 | 
	
		
			
				|  |  | -+       * to the set collected since the first Begin() call */
 | 
	
		
			
				|  |  | -+      m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else if (hardwareClipping)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    /* Apply the translation offset to the vertices from the cache after
 | 
	
		
			
				|  |  | -+     * appending them to the set collected since the first Begin() call */
 | 
	
		
			
				|  |  | -+    m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
 | 
	
		
			
				|  |  | -+    SVertex *v;
 | 
	
		
			
				|  |  | -+    for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      v->x += dynamicPos.m_x;
 | 
	
		
			
				|  |  | -+      v->y += dynamicPos.m_y;
 | 
	
		
			
				|  |  | -+      v->z += dynamicPos.m_z;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  /* Append the new vertices (from the cache or otherwise) to the set collected
 | 
	
		
			
				|  |  | --   * since the first Begin() call */
 | 
	
		
			
				|  |  | --  m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
 | 
	
		
			
				|  |  | -+  if (!hardwareClipping)
 | 
	
		
			
				|  |  | -+    /* Append the new vertices (from the cache or otherwise) to the set collected
 | 
	
		
			
				|  |  | -+     * since the first Begin() call */
 | 
	
		
			
				|  |  | -+    m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   End();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index 7cb4669..78445ab 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -170,6 +170,7 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   CStdString m_strFileName;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   CGUIFontCache<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> m_staticCache;
 | 
	
		
			
				|  |  | -+  CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue> m_dynamicCache;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -   virtual bool FirstBegin() = 0;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 10eeb73ca15798de26abd5f8846214c8938f8b42 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 8 Jan 2014 12:16:33 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 25/94] Rewrite of scrolling text code.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -No longer shuffles the string round to minimise the number of characters
 | 
	
		
			
				|  |  | -before the clipping rectangle; this doesn't save much on rendering time but
 | 
	
		
			
				|  |  | -does harm the effectiveness of the cache. Now uses a pixel offset into the
 | 
	
		
			
				|  |  | -string rather than a character + pixel offset, and plots the entire string
 | 
	
		
			
				|  |  | -every time (execpt when the wrap point is visible, in which case the entire
 | 
	
		
			
				|  |  | -string is plotted twice).
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -It also makes motion smoother, because (possibly unintentionally) the
 | 
	
		
			
				|  |  | -previous code preferred to align the scroll offset with character boundaries.
 | 
	
		
			
				|  |  | -This would lead to uneven changes of position, especially when the width of
 | 
	
		
			
				|  |  | -the character currently being scrolled off the edge was only slightly more
 | 
	
		
			
				|  |  | -than an integral multiple of the scroll increment.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFadeLabelControl.cpp |   8 +--
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFont.cpp             | 123 +++++++++++++-----------------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFont.h               |  17 ++---
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIRSSControl.cpp       |   6 +-
 | 
	
		
			
				|  |  | - xbmc/utils/RssReader.cpp            |   2 +-
 | 
	
		
			
				|  |  | - xbmc/utils/RssReader.h              |   2 +-
 | 
	
		
			
				|  |  | - 6 files changed, 58 insertions(+), 100 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFadeLabelControl.cpp b/xbmc/guilib/GUIFadeLabelControl.cpp
 | 
	
		
			
				|  |  | -index d594c04..86ee73a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFadeLabelControl.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFadeLabelControl.cpp
 | 
	
		
			
				|  |  | -@@ -109,18 +109,14 @@ void CGUIFadeLabelControl::Process(unsigned int currentTime, CDirtyRegionList &d
 | 
	
		
			
				|  |  | -     bool moveToNextLabel = false;
 | 
	
		
			
				|  |  | -     if (!m_scrollOut)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      vecText text;
 | 
	
		
			
				|  |  | --      m_textLayout.GetFirstText(text);
 | 
	
		
			
				|  |  | --      if (m_scrollInfo.characterPos && m_scrollInfo.characterPos < text.size())
 | 
	
		
			
				|  |  | --        text.erase(text.begin(), text.begin() + min((int)m_scrollInfo.characterPos - 1, (int)text.size()));
 | 
	
		
			
				|  |  | --      if (m_label.font->GetTextWidth(text) < m_width)
 | 
	
		
			
				|  |  | -+      if (m_scrollInfo.pixelPos + m_width > m_scrollInfo.m_textWidth)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -         if (m_fadeAnim.GetProcess() != ANIM_PROCESS_NORMAL)
 | 
	
		
			
				|  |  | -           m_fadeAnim.QueueAnimation(ANIM_PROCESS_NORMAL);
 | 
	
		
			
				|  |  | -         moveToNextLabel = true;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    else if (m_scrollInfo.characterPos > m_textLayout.GetTextLength())
 | 
	
		
			
				|  |  | -+    else if (m_scrollInfo.pixelPos > m_scrollInfo.m_textWidth)
 | 
	
		
			
				|  |  | -       moveToNextLabel = true;
 | 
	
		
			
				|  |  | -     
 | 
	
		
			
				|  |  | -     // apply the fading animation
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFont.cpp b/xbmc/guilib/GUIFont.cpp
 | 
	
		
			
				|  |  | -index a7ee668..eb8efdb 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFont.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFont.cpp
 | 
	
		
			
				|  |  | -@@ -36,7 +36,12 @@ CScrollInfo::CScrollInfo(unsigned int wait /* = 50 */, float pos /* = 0 */,
 | 
	
		
			
				|  |  | -     initialWait = wait;
 | 
	
		
			
				|  |  | -     initialPos = pos;
 | 
	
		
			
				|  |  | -     SetSpeed(speed ? speed : defaultSpeed);
 | 
	
		
			
				|  |  | --    g_charsetConverter.utf8ToW(scrollSuffix, suffix);
 | 
	
		
			
				|  |  | -+    CStdStringW wsuffix;
 | 
	
		
			
				|  |  | -+    g_charsetConverter.utf8ToW(scrollSuffix, wsuffix);
 | 
	
		
			
				|  |  | -+    suffix.clear();
 | 
	
		
			
				|  |  | -+    suffix.reserve(wsuffix.size());
 | 
	
		
			
				|  |  | -+    for (vecText::size_type i = 0; i < wsuffix.size(); i++)
 | 
	
		
			
				|  |  | -+      suffix.push_back(wsuffix[i]);
 | 
	
		
			
				|  |  | -     Reset();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -115,11 +120,12 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   // draw at our scroll position
 | 
	
		
			
				|  |  | -   // we handle the scrolling as follows:
 | 
	
		
			
				|  |  | --  //   We scroll on a per-pixel basis up until we have scrolled the first character outside
 | 
	
		
			
				|  |  | --  //   of our viewport, whereby we cycle the string around, and reset the scroll position.
 | 
	
		
			
				|  |  | --  //
 | 
	
		
			
				|  |  | --  //   pixelPos is the amount in pixels to move the string by.
 | 
	
		
			
				|  |  | --  //   characterPos is the amount in characters to rotate the string by.
 | 
	
		
			
				|  |  | -+  //   We scroll on a per-pixel basis (eschewing the use of character indices
 | 
	
		
			
				|  |  | -+  //   which were also in use previously). The complete string, including suffix,
 | 
	
		
			
				|  |  | -+  //   is plotted to achieve the desired effect - normally just the one time, but
 | 
	
		
			
				|  |  | -+  //   if there is a wrap point within the viewport then it will be plotted twice.
 | 
	
		
			
				|  |  | -+  //   If the string is smaller than the viewport, then it may be plotted even
 | 
	
		
			
				|  |  | -+  //   more times than that.
 | 
	
		
			
				|  |  | -   //
 | 
	
		
			
				|  |  | -   if (scrollInfo.waitTime)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -135,54 +141,19 @@ bool CGUIFont::UpdateScrollInfo(const vecText &text, CScrollInfo &scrollInfo)
 | 
	
		
			
				|  |  | -   // move along by the appropriate scroll amount
 | 
	
		
			
				|  |  | -   float scrollAmount = fabs(scrollInfo.GetPixelsPerFrame() * g_graphicsContext.GetGUIScaleX());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (scrollInfo.pixelSpeed > 0)
 | 
	
		
			
				|  |  | -+  if (!scrollInfo.m_widthValid)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    // we want to move scrollAmount, grab the next character
 | 
	
		
			
				|  |  | --    float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
 | 
	
		
			
				|  |  | --    if (scrollInfo.pixelPos + scrollAmount < charWidth)
 | 
	
		
			
				|  |  | --      scrollInfo.pixelPos += scrollAmount;  // within the current character
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    { // past the current character, decrement scrollAmount by the charWidth and move to the next character
 | 
	
		
			
				|  |  | --      while (scrollInfo.pixelPos + scrollAmount >= charWidth)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        scrollAmount -= (charWidth - scrollInfo.pixelPos);
 | 
	
		
			
				|  |  | --        scrollInfo.pixelPos = 0;
 | 
	
		
			
				|  |  | --        scrollInfo.characterPos++;
 | 
	
		
			
				|  |  | --        if (scrollInfo.characterPos >= text.size() + scrollInfo.suffix.size())
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          scrollInfo.Reset();
 | 
	
		
			
				|  |  | --          break;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --        charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else if (scrollInfo.pixelSpeed < 0)
 | 
	
		
			
				|  |  | --  { // scrolling backwards
 | 
	
		
			
				|  |  | --    // we want to move scrollAmount, grab the next character
 | 
	
		
			
				|  |  | --    float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
 | 
	
		
			
				|  |  | --    if (scrollInfo.pixelPos + scrollAmount < charWidth)
 | 
	
		
			
				|  |  | --      scrollInfo.pixelPos += scrollAmount;  // within the current character
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    { // past the current character, decrement scrollAmount by the charWidth and move to the next character
 | 
	
		
			
				|  |  | --      while (scrollInfo.pixelPos + scrollAmount >= charWidth)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        scrollAmount -= (charWidth - scrollInfo.pixelPos);
 | 
	
		
			
				|  |  | --        scrollInfo.pixelPos = 0;
 | 
	
		
			
				|  |  | --        if (scrollInfo.characterPos == 0)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          scrollInfo.Reset();
 | 
	
		
			
				|  |  | --          scrollInfo.characterPos = text.size() + scrollInfo.suffix.size() - 1;
 | 
	
		
			
				|  |  | --          break;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --        scrollInfo.characterPos--;
 | 
	
		
			
				|  |  | --        charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    /* Calculate the pixel width of the complete string */
 | 
	
		
			
				|  |  | -+    scrollInfo.m_textWidth = GetTextWidth(text);
 | 
	
		
			
				|  |  | -+    scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix);
 | 
	
		
			
				|  |  | -+    scrollInfo.m_widthValid = true;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  scrollInfo.pixelPos += scrollAmount;
 | 
	
		
			
				|  |  | -+  assert(scrollInfo.m_totalWidth != 0);
 | 
	
		
			
				|  |  | -+  while (scrollInfo.pixelPos >= scrollInfo.m_totalWidth)
 | 
	
		
			
				|  |  | -+    scrollInfo.pixelPos -= scrollInfo.m_totalWidth;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if(scrollInfo.characterPos != old.characterPos
 | 
	
		
			
				|  |  | --  || scrollInfo.pixelPos     != old.pixelPos)
 | 
	
		
			
				|  |  | -+  if (scrollInfo.pixelPos != old.pixelPos)
 | 
	
		
			
				|  |  | -     return true;
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -@@ -194,39 +165,27 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo
 | 
	
		
			
				|  |  | -   if (!m_font) return;
 | 
	
		
			
				|  |  | -   if (!shadowColor) shadowColor = m_shadowColor;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  float spaceWidth = GetCharWidth(L' ');
 | 
	
		
			
				|  |  | --  // max chars on screen + extra margin chars
 | 
	
		
			
				|  |  | --  vecText::size_type maxChars =
 | 
	
		
			
				|  |  | --    std::min<vecText::size_type>(
 | 
	
		
			
				|  |  | --      (text.size() + (vecText::size_type)scrollInfo.suffix.size()),
 | 
	
		
			
				|  |  | --      (vecText::size_type)((maxWidth * 1.05f) / spaceWidth));
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   if (!text.size() || ClippedRegionIsEmpty(x, y, maxWidth, alignment))
 | 
	
		
			
				|  |  | -     return; // nothing to render
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  maxWidth = ROUND((maxWidth + scrollInfo.pixelPos) / g_graphicsContext.GetGUIScaleX());
 | 
	
		
			
				|  |  | -+  if (!scrollInfo.m_widthValid)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    /* Calculate the pixel width of the complete string */
 | 
	
		
			
				|  |  | -+    scrollInfo.m_textWidth = GetTextWidth(text);
 | 
	
		
			
				|  |  | -+    scrollInfo.m_totalWidth = scrollInfo.m_textWidth + GetTextWidth(scrollInfo.suffix);
 | 
	
		
			
				|  |  | -+    scrollInfo.m_widthValid = true;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  assert(scrollInfo.m_totalWidth != 0);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  float textPixelWidth = ROUND(scrollInfo.m_textWidth / g_graphicsContext.GetGUIScaleX());
 | 
	
		
			
				|  |  | -+  float suffixPixelWidth = ROUND((scrollInfo.m_totalWidth - scrollInfo.m_textWidth) / g_graphicsContext.GetGUIScaleX());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  float charWidth = GetCharWidth(scrollInfo.GetCurrentChar(text));
 | 
	
		
			
				|  |  | -   float offset;
 | 
	
		
			
				|  |  | -   if(scrollInfo.pixelSpeed >= 0)
 | 
	
		
			
				|  |  | -     offset = scrollInfo.pixelPos;
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | --    offset = charWidth - scrollInfo.pixelPos;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // Now rotate our string as needed, only take a slightly larger then visible part of the text.
 | 
	
		
			
				|  |  | --  unsigned int pos = scrollInfo.characterPos;
 | 
	
		
			
				|  |  | --  vecText renderText;
 | 
	
		
			
				|  |  | --  renderText.reserve(maxChars);
 | 
	
		
			
				|  |  | --  for (vecText::size_type i = 0; i < maxChars; i++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if (pos >= text.size() + scrollInfo.suffix.size())
 | 
	
		
			
				|  |  | --      pos = 0;
 | 
	
		
			
				|  |  | --    if (pos < text.size())
 | 
	
		
			
				|  |  | --      renderText.push_back(text[pos]);
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --      renderText.push_back(scrollInfo.suffix[pos - text.size()]);
 | 
	
		
			
				|  |  | --    pos++;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    offset = scrollInfo.m_totalWidth - scrollInfo.pixelPos;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   vecColors renderColors;
 | 
	
		
			
				|  |  | -   for (unsigned int i = 0; i < colors.size(); i++)
 | 
	
		
			
				|  |  | -@@ -239,9 +198,17 @@ void CGUIFont::DrawScrollingText(float x, float y, const vecColors &colors, colo
 | 
	
		
			
				|  |  | -     vecColors shadowColors;
 | 
	
		
			
				|  |  | -     for (unsigned int i = 0; i < renderColors.size(); i++)
 | 
	
		
			
				|  |  | -       shadowColors.push_back((renderColors[i] & 0xff000000) != 0 ? shadowColor : 0);
 | 
	
		
			
				|  |  | --    m_font->DrawTextInternal(x - offset + 1, y + 1, shadowColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll);
 | 
	
		
			
				|  |  | -+    for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      m_font->DrawTextInternal(x + dx + 1, y + 1, shadowColors, text, alignment, textPixelWidth, scroll);
 | 
	
		
			
				|  |  | -+      m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth + 1, y + 1, shadowColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  for (float dx = -offset; dx < maxWidth; dx += scrollInfo.m_totalWidth)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_font->DrawTextInternal(x + dx, y, renderColors, text, alignment, textPixelWidth, scroll);
 | 
	
		
			
				|  |  | -+    m_font->DrawTextInternal(x + dx + scrollInfo.m_textWidth, y, renderColors, scrollInfo.suffix, alignment, suffixPixelWidth, scroll);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  m_font->DrawTextInternal(x - offset, y, renderColors, renderText, alignment, maxWidth + m_font->GetLineHeight(2.0f), scroll);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   g_graphicsContext.RestoreClipRegion();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFont.h b/xbmc/guilib/GUIFont.h
 | 
	
		
			
				|  |  | -index c55db48..09cf9b3 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFont.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFont.h
 | 
	
		
			
				|  |  | -@@ -64,7 +64,6 @@ class CScrollInfo
 | 
	
		
			
				|  |  | -   void Reset()
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     waitTime = initialWait;
 | 
	
		
			
				|  |  | --    characterPos = 0;
 | 
	
		
			
				|  |  | -     // pixelPos is where we start the current letter, so is measured
 | 
	
		
			
				|  |  | -     // to the left of the text rendering's left edge.  Thus, a negative
 | 
	
		
			
				|  |  | -     // value will mean the text starts to the right
 | 
	
		
			
				|  |  | -@@ -72,25 +71,19 @@ class CScrollInfo
 | 
	
		
			
				|  |  | -     // privates:
 | 
	
		
			
				|  |  | -     m_averageFrameTime = 1000.f / abs(defaultSpeed);
 | 
	
		
			
				|  |  | -     m_lastFrameTime = 0;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  uint32_t GetCurrentChar(const vecText &text) const
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    assert(text.size());
 | 
	
		
			
				|  |  | --    if (characterPos < text.size())
 | 
	
		
			
				|  |  | --      return text[characterPos];
 | 
	
		
			
				|  |  | --    else if (characterPos < text.size() + suffix.size())
 | 
	
		
			
				|  |  | --      return suffix[characterPos - text.size()];
 | 
	
		
			
				|  |  | --    return text[0];
 | 
	
		
			
				|  |  | -+    m_widthValid = false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   float GetPixelsPerFrame();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   float pixelPos;
 | 
	
		
			
				|  |  | -   float pixelSpeed;
 | 
	
		
			
				|  |  | -   unsigned int waitTime;
 | 
	
		
			
				|  |  | --  unsigned int characterPos;
 | 
	
		
			
				|  |  | -   unsigned int initialWait;
 | 
	
		
			
				|  |  | -   float initialPos;
 | 
	
		
			
				|  |  | --  CStdStringW suffix;
 | 
	
		
			
				|  |  | -+  vecText suffix;
 | 
	
		
			
				|  |  | -+  mutable float m_textWidth;
 | 
	
		
			
				|  |  | -+  mutable float m_totalWidth;
 | 
	
		
			
				|  |  | -+  mutable bool m_widthValid;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   static const int defaultSpeed = 60;
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIRSSControl.cpp b/xbmc/guilib/GUIRSSControl.cpp
 | 
	
		
			
				|  |  | -index 712e118..203c138 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIRSSControl.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIRSSControl.cpp
 | 
	
		
			
				|  |  | -@@ -119,7 +119,9 @@ void CGUIRSSControl::Process(unsigned int currentTime, CDirtyRegionList &dirtyre
 | 
	
		
			
				|  |  | -       dirty = true;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       if (CRssManager::Get().GetReader(GetID(), GetParentID(), this, m_pReader))
 | 
	
		
			
				|  |  | --        m_scrollInfo.characterPos = m_pReader->m_SavedScrollPos;
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        m_scrollInfo.pixelPos = m_pReader->m_savedScrollPixelPos;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -       else
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -         if (m_strRSSTags != "")
 | 
	
		
			
				|  |  | -@@ -177,7 +179,7 @@ void CGUIRSSControl::Render()
 | 
	
		
			
				|  |  | -     if (m_pReader)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       m_pReader->CheckForUpdates();
 | 
	
		
			
				|  |  | --      m_pReader->m_SavedScrollPos = m_scrollInfo.characterPos;
 | 
	
		
			
				|  |  | -+      m_pReader->m_savedScrollPixelPos = m_scrollInfo.pixelPos;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   CGUIControl::Render();
 | 
	
		
			
				|  |  | -diff --git a/xbmc/utils/RssReader.cpp b/xbmc/utils/RssReader.cpp
 | 
	
		
			
				|  |  | -index b1e53b7..f68597a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/utils/RssReader.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/utils/RssReader.cpp
 | 
	
		
			
				|  |  | -@@ -54,7 +54,7 @@ CRssReader::CRssReader() : CThread("RSSReader")
 | 
	
		
			
				|  |  | -   m_pObserver = NULL;
 | 
	
		
			
				|  |  | -   m_spacesBetweenFeeds = 0;
 | 
	
		
			
				|  |  | -   m_bIsRunning = false;
 | 
	
		
			
				|  |  | --  m_SavedScrollPos = 0;
 | 
	
		
			
				|  |  | -+  m_savedScrollPixelPos = 0;
 | 
	
		
			
				|  |  | -   m_rtlText = false;
 | 
	
		
			
				|  |  | -   m_requestRefresh = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/utils/RssReader.h b/xbmc/utils/RssReader.h
 | 
	
		
			
				|  |  | -index 2c6f366..b74faf2 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/utils/RssReader.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/utils/RssReader.h
 | 
	
		
			
				|  |  | -@@ -43,7 +43,7 @@ class CRssReader : public CThread
 | 
	
		
			
				|  |  | -   void SetObserver(IRssObserver* observer);
 | 
	
		
			
				|  |  | -   void CheckForUpdates();
 | 
	
		
			
				|  |  | -   void requestRefresh();
 | 
	
		
			
				|  |  | --  unsigned int m_SavedScrollPos;
 | 
	
		
			
				|  |  | -+  float m_savedScrollPixelPos;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -   void Process();
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7064920379f68a7f6114813db8ad40a21c4957cc Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Mon, 27 Jan 2014 23:21:10 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 26/94] Move the application of the translation offsets into
 | 
	
		
			
				|  |  | - the GLES code. Still all pure software at this stage. Main change is in the
 | 
	
		
			
				|  |  | - data types at the interface between CGUIFontTTFBase and CGUIFontTTFGL. The
 | 
	
		
			
				|  |  | - old way (array of vertices in m_vertex) are retained in addition, for the
 | 
	
		
			
				|  |  | - sake`of cases that need to use software clipping on GLES, as well as for DX
 | 
	
		
			
				|  |  | - and GL support where the new scheme is not (yet?) used.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp   | 19 +++---------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h     | 17 +++++++++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp | 72 ++++++++++++++++++++++++++++++++------------
 | 
	
		
			
				|  |  | - 3 files changed, 73 insertions(+), 35 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 73f0e50..ad0a53b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -215,6 +215,7 @@ void CGUIFontTTFBase::Clear()
 | 
	
		
			
				|  |  | -     g_freeTypeLibrary.ReleaseStroker(m_stroker);
 | 
	
		
			
				|  |  | -   m_stroker = NULL;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_vertexTrans.clear();
 | 
	
		
			
				|  |  | -   m_vertex.clear();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -310,6 +311,7 @@ void CGUIFontTTFBase::Begin()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (m_nestedBeginCount == 0 && m_texture != NULL && FirstBegin())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -+    m_vertexTrans.clear();
 | 
	
		
			
				|  |  | -     m_vertex.clear();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   // Keep track of the nested begin/end calls.
 | 
	
		
			
				|  |  | -@@ -457,23 +459,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | -         cursorX += ch->advance;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     if (hardwareClipping)
 | 
	
		
			
				|  |  | --      /* Append the new vertices (which we have just constructed in the cache)
 | 
	
		
			
				|  |  | --       * to the set collected since the first Begin() call */
 | 
	
		
			
				|  |  | --      m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
 | 
	
		
			
				|  |  | -+      m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices));
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   else if (hardwareClipping)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    /* Apply the translation offset to the vertices from the cache after
 | 
	
		
			
				|  |  | --     * appending them to the set collected since the first Begin() call */
 | 
	
		
			
				|  |  | --    m_vertex.insert(m_vertex.end(), vertices.begin(), vertices.end());
 | 
	
		
			
				|  |  | --    SVertex *v;
 | 
	
		
			
				|  |  | --    for (v = &*m_vertex.end() - vertices.size(); v != &*m_vertex.end(); v++)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      v->x += dynamicPos.m_x;
 | 
	
		
			
				|  |  | --      v->y += dynamicPos.m_y;
 | 
	
		
			
				|  |  | --      v->z += dynamicPos.m_z;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices));
 | 
	
		
			
				|  |  | -   if (!hardwareClipping)
 | 
	
		
			
				|  |  | -     /* Append the new vertices (from the cache or otherwise) to the set collected
 | 
	
		
			
				|  |  | -      * since the first Begin() call */
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index 78445ab..c71f90d 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -61,6 +61,14 @@ struct SVertex
 | 
	
		
			
				|  |  | -   unsigned char r, g, b, a;
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -   float u, v;
 | 
	
		
			
				|  |  | -+  struct SVertex Offset(float translate[3]) const
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    SVertex out = *this;
 | 
	
		
			
				|  |  | -+    out.x += translate[0];
 | 
	
		
			
				|  |  | -+    out.y += translate[1];
 | 
	
		
			
				|  |  | -+    out.z += translate[2];
 | 
	
		
			
				|  |  | -+    return out;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -160,6 +168,15 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   bool m_bTextureLoaded;
 | 
	
		
			
				|  |  | -   unsigned int m_nTexture;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  struct CTranslatedVertices
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    float translateX;
 | 
	
		
			
				|  |  | -+    float translateY;
 | 
	
		
			
				|  |  | -+    float translateZ;
 | 
	
		
			
				|  |  | -+    const std::vector<SVertex> *vertexBuffer;
 | 
	
		
			
				|  |  | -+    CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {}
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+  std::vector<CTranslatedVertices> m_vertexTrans;
 | 
	
		
			
				|  |  | -   std::vector<SVertex> m_vertex;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   float    m_textureScaleX;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index cb56987..f6aa081 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -146,34 +146,65 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -   GLint colLoc  = g_Windowing.GUIShaderGetCol();
 | 
	
		
			
				|  |  | -   GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // stack object until VBOs will be used
 | 
	
		
			
				|  |  | --  std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
 | 
	
		
			
				|  |  | --  SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | -+  // Enable the attributes used by this shader
 | 
	
		
			
				|  |  | -+  glEnableVertexAttribArray(posLoc);
 | 
	
		
			
				|  |  | -+  glEnableVertexAttribArray(colLoc);
 | 
	
		
			
				|  |  | -+  glEnableVertexAttribArray(tex0Loc);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  for (size_t i=0; i<m_vertex.size(); i+=4)
 | 
	
		
			
				|  |  | -+  if (m_vertex.size() > 0)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    *vertices++ = m_vertex[i];
 | 
	
		
			
				|  |  | --    *vertices++ = m_vertex[i+1];
 | 
	
		
			
				|  |  | --    *vertices++ = m_vertex[i+2];
 | 
	
		
			
				|  |  | -+    // Deal with vertices that had to use software clipping
 | 
	
		
			
				|  |  | -+    std::vector<SVertex> vecVertices( 6 * (m_vertex.size() / 4) );
 | 
	
		
			
				|  |  | -+    SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    *vertices++ = m_vertex[i+1];
 | 
	
		
			
				|  |  | --    *vertices++ = m_vertex[i+3];
 | 
	
		
			
				|  |  | --    *vertices++ = m_vertex[i+2];
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    for (size_t i=0; i<m_vertex.size(); i+=4)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      *vertices++ = m_vertex[i];
 | 
	
		
			
				|  |  | -+      *vertices++ = m_vertex[i+1];
 | 
	
		
			
				|  |  | -+      *vertices++ = m_vertex[i+2];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | -+      *vertices++ = m_vertex[i+1];
 | 
	
		
			
				|  |  | -+      *vertices++ = m_vertex[i+3];
 | 
	
		
			
				|  |  | -+      *vertices++ = m_vertex[i+2];
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | --  // Normalize color values. Does not affect Performance at all.
 | 
	
		
			
				|  |  | --  glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | --  glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+    vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  glEnableVertexAttribArray(posLoc);
 | 
	
		
			
				|  |  | --  glEnableVertexAttribArray(colLoc);
 | 
	
		
			
				|  |  | --  glEnableVertexAttribArray(tex0Loc);
 | 
	
		
			
				|  |  | -+    glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | -+    // Normalize color values. Does not affect Performance at all.
 | 
	
		
			
				|  |  | -+    glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | -+    glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  if (m_vertexTrans.size() > 0)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    // Deal with the vertices that can be hardware clipped and therefore translated
 | 
	
		
			
				|  |  | -+    std::vector<SVertex> vecVertices;
 | 
	
		
			
				|  |  | -+    for (size_t i = 0; i < m_vertexTrans.size(); i++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ };
 | 
	
		
			
				|  |  | -+      for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate));
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate));
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
 | 
	
		
			
				|  |  | -+    glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | -+    // Normalize color values. Does not affect Performance at all.
 | 
	
		
			
				|  |  | -+    glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | -+    glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  // Disable the attributes used by this shader
 | 
	
		
			
				|  |  | -   glDisableVertexAttribArray(posLoc);
 | 
	
		
			
				|  |  | -   glDisableVertexAttribArray(colLoc);
 | 
	
		
			
				|  |  | -   glDisableVertexAttribArray(tex0Loc);
 | 
	
		
			
				|  |  | -@@ -201,6 +232,7 @@ CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
 | 
	
		
			
				|  |  | -   if (m_textureHeight < newHeight)
 | 
	
		
			
				|  |  | -     CLog::Log(LOGWARNING, "%s: allocated new texture with height of %d, requested %d", __FUNCTION__, m_textureHeight, newHeight);
 | 
	
		
			
				|  |  | -   m_staticCache.Flush();
 | 
	
		
			
				|  |  | -+  m_dynamicCache.Flush();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   memset(newTexture->GetPixels(), 0, m_textureHeight * newTexture->GetPitch());
 | 
	
		
			
				|  |  | -   if (m_texture)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 476fce7bc2897e8898f4392809d934b0d5f46518 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 15 Jan 2014 15:28:06 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 27/94] Rather than applying the translation offsets to the
 | 
	
		
			
				|  |  | - vertices, now applies them to the model view matrix from the top of the
 | 
	
		
			
				|  |  | - matrix stack and pushes it over to OpenGL. The vertices themselves are still
 | 
	
		
			
				|  |  | - all held client-side.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h                 |  8 -------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp             | 40 +++++++++++++++++++++-----------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIShader.h                  |  1 +
 | 
	
		
			
				|  |  | - xbmc/rendering/gles/RenderSystemGLES.cpp |  8 +++++++
 | 
	
		
			
				|  |  | - xbmc/rendering/gles/RenderSystemGLES.h   |  1 +
 | 
	
		
			
				|  |  | - 5 files changed, 36 insertions(+), 22 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index c71f90d..fde2085 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -61,14 +61,6 @@ struct SVertex
 | 
	
		
			
				|  |  | -   unsigned char r, g, b, a;
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -   float u, v;
 | 
	
		
			
				|  |  | --  struct SVertex Offset(float translate[3]) const
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    SVertex out = *this;
 | 
	
		
			
				|  |  | --    out.x += translate[0];
 | 
	
		
			
				|  |  | --    out.y += translate[1];
 | 
	
		
			
				|  |  | --    out.z += translate[2];
 | 
	
		
			
				|  |  | --    return out;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index f6aa081..fbffaa0 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -29,6 +29,7 @@
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - #include "utils/GLUtils.h"
 | 
	
		
			
				|  |  | - #include "windowing/WindowingFactory.h"
 | 
	
		
			
				|  |  | -+#include "guilib/MatrixGLES.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - // stuff for freetype
 | 
	
		
			
				|  |  | - #include <ft2build.h>
 | 
	
		
			
				|  |  | -@@ -145,6 +146,7 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -   GLint posLoc  = g_Windowing.GUIShaderGetPos();
 | 
	
		
			
				|  |  | -   GLint colLoc  = g_Windowing.GUIShaderGetCol();
 | 
	
		
			
				|  |  | -   GLint tex0Loc = g_Windowing.GUIShaderGetCoord0();
 | 
	
		
			
				|  |  | -+  GLint modelLoc = g_Windowing.GUIShaderGetModel();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Enable the attributes used by this shader
 | 
	
		
			
				|  |  | -   glEnableVertexAttribArray(posLoc);
 | 
	
		
			
				|  |  | -@@ -183,25 +185,35 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -     std::vector<SVertex> vecVertices;
 | 
	
		
			
				|  |  | -     for (size_t i = 0; i < m_vertexTrans.size(); i++)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      float translate[3] = { m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ };
 | 
	
		
			
				|  |  | -+      // Apply the translation to the currently active (top-of-stack) model view matrix
 | 
	
		
			
				|  |  | -+      g_matrices.MatrixMode(MM_MODELVIEW);
 | 
	
		
			
				|  |  | -+      g_matrices.PushMatrix();
 | 
	
		
			
				|  |  | -+      g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ);
 | 
	
		
			
				|  |  | -+      glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      vecVertices.clear();
 | 
	
		
			
				|  |  | -       for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j].Offset(translate));
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1].Offset(translate));
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3].Offset(translate));
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2].Offset(translate));
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]);
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]);
 | 
	
		
			
				|  |  | -+        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | -+      SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | --    // Normalize color values. Does not affect Performance at all.
 | 
	
		
			
				|  |  | --    glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | --    glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+      glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | -+      // Normalize color values. Does not affect Performance at all.
 | 
	
		
			
				|  |  | -+      glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | -+      glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
 | 
	
		
			
				|  |  | -+      glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      g_matrices.PopMatrix();
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    // Restore the original model view matrix
 | 
	
		
			
				|  |  | -+    glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Disable the attributes used by this shader
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIShader.h b/xbmc/guilib/GUIShader.h
 | 
	
		
			
				|  |  | -index 86ce4cc..ba01956 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIShader.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIShader.h
 | 
	
		
			
				|  |  | -@@ -41,6 +41,7 @@ class CGUIShader : public CGLSLShaderProgram
 | 
	
		
			
				|  |  | -   GLint GetCord1Loc() { return m_hCord1; }
 | 
	
		
			
				|  |  | -   GLint GetUniColLoc() { return m_hUniCol; }
 | 
	
		
			
				|  |  | -   GLint GetCoord0MatrixLoc() { return m_hCoord0Matrix; }
 | 
	
		
			
				|  |  | -+  GLint GetModelLoc() { return m_hModel; }
 | 
	
		
			
				|  |  | -   bool HardwareClipIsPossible() { return m_clipPossible; }
 | 
	
		
			
				|  |  | -   GLfloat GetClipXFactor() { return m_clipXFactor; }
 | 
	
		
			
				|  |  | -   GLfloat GetClipXOffset() { return m_clipXOffset; }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/rendering/gles/RenderSystemGLES.cpp b/xbmc/rendering/gles/RenderSystemGLES.cpp
 | 
	
		
			
				|  |  | -index deb3afc..0904d1f 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/rendering/gles/RenderSystemGLES.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/rendering/gles/RenderSystemGLES.cpp
 | 
	
		
			
				|  |  | -@@ -691,4 +691,12 @@ bool CRenderSystemGLES::SupportsStereo(RENDER_STEREO_MODE mode)
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+GLint CRenderSystemGLES::GUIShaderGetModel()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (m_pGUIshader[m_method])
 | 
	
		
			
				|  |  | -+    return m_pGUIshader[m_method]->GetModelLoc();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return -1;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/rendering/gles/RenderSystemGLES.h b/xbmc/rendering/gles/RenderSystemGLES.h
 | 
	
		
			
				|  |  | -index 81ee49e..d2f9cd1 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/rendering/gles/RenderSystemGLES.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/rendering/gles/RenderSystemGLES.h
 | 
	
		
			
				|  |  | -@@ -91,6 +91,7 @@ class CRenderSystemGLES : public CRenderSystemBase
 | 
	
		
			
				|  |  | -   GLint GUIShaderGetCoord1();
 | 
	
		
			
				|  |  | -   GLint GUIShaderGetUniCol();
 | 
	
		
			
				|  |  | -   GLint GUIShaderGetCoord0Matrix();
 | 
	
		
			
				|  |  | -+  GLint GUIShaderGetModel();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   virtual void SetVSyncImpl(bool enable) = 0;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 473ccc4cbe616f672a72108d2ec98107780ac7da Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 29 Jan 2014 13:21:19 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 28/94] Enable hardware clipping.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp   | 4 ++--
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h     | 5 ++++-
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp | 6 ++++++
 | 
	
		
			
				|  |  | - 3 files changed, 12 insertions(+), 3 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index ad0a53b..4dc4c8e 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -459,10 +459,10 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | -         cursorX += ch->advance;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     if (hardwareClipping)
 | 
	
		
			
				|  |  | --      m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices));
 | 
	
		
			
				|  |  | -+      m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion()));
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   else if (hardwareClipping)
 | 
	
		
			
				|  |  | --    m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices));
 | 
	
		
			
				|  |  | -+    m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion()));
 | 
	
		
			
				|  |  | -   if (!hardwareClipping)
 | 
	
		
			
				|  |  | -     /* Append the new vertices (from the cache or otherwise) to the set collected
 | 
	
		
			
				|  |  | -      * since the first Begin() call */
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index fde2085..5e7c31f 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -27,6 +27,8 @@
 | 
	
		
			
				|  |  | -  *
 | 
	
		
			
				|  |  | -  */
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#include "Geometry.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - // forward definition
 | 
	
		
			
				|  |  | - class CBaseTexture;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -166,7 +168,8 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | -     float translateY;
 | 
	
		
			
				|  |  | -     float translateZ;
 | 
	
		
			
				|  |  | -     const std::vector<SVertex> *vertexBuffer;
 | 
	
		
			
				|  |  | --    CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer) {}
 | 
	
		
			
				|  |  | -+    CRect clip;
 | 
	
		
			
				|  |  | -+    CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
 | 
	
		
			
				|  |  | -   };
 | 
	
		
			
				|  |  | -   std::vector<CTranslatedVertices> m_vertexTrans;
 | 
	
		
			
				|  |  | -   std::vector<SVertex> m_vertex;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index fbffaa0..b7618e1 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -185,6 +185,10 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -     std::vector<SVertex> vecVertices;
 | 
	
		
			
				|  |  | -     for (size_t i = 0; i < m_vertexTrans.size(); i++)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -+      // Apply the clip rectangle
 | 
	
		
			
				|  |  | -+      CRect clip = g_Windowing.ClipRectToScissorRect(m_vertexTrans[i].clip);
 | 
	
		
			
				|  |  | -+      g_graphicsContext.SetScissors(clip);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -       // Apply the translation to the currently active (top-of-stack) model view matrix
 | 
	
		
			
				|  |  | -       g_matrices.MatrixMode(MM_MODELVIEW);
 | 
	
		
			
				|  |  | -       g_matrices.PushMatrix();
 | 
	
		
			
				|  |  | -@@ -212,6 +216,8 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       g_matrices.PopMatrix();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+    // Restore the original scissor rectangle
 | 
	
		
			
				|  |  | -+    g_graphicsContext.ResetScissors();
 | 
	
		
			
				|  |  | -     // Restore the original model view matrix
 | 
	
		
			
				|  |  | -     glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From f39c4523a1c05425fb94d3536a510709784f9558 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 15 Jan 2014 15:32:51 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 29/94] Move the vertex data across to a vertex buffer object
 | 
	
		
			
				|  |  | - just prior to drawing.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp | 24 +++++++++++++++++++-----
 | 
	
		
			
				|  |  | - 1 file changed, 19 insertions(+), 5 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index b7618e1..0df3749 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -207,12 +207,24 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -       SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, x));
 | 
	
		
			
				|  |  | --      // Normalize color values. Does not affect Performance at all.
 | 
	
		
			
				|  |  | --      glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, r));
 | 
	
		
			
				|  |  | --      glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (char*)vertices + offsetof(SVertex, u));
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+      // Generate a unique buffer object name and put it in vertexBuffer
 | 
	
		
			
				|  |  | -+      GLuint vertexBuffer;
 | 
	
		
			
				|  |  | -+      glGenBuffers(1, &vertexBuffer);
 | 
	
		
			
				|  |  | -+      // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
 | 
	
		
			
				|  |  | -+      glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
 | 
	
		
			
				|  |  | -+      // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+      // binding point (i.e. our buffer object) and initialise it from the
 | 
	
		
			
				|  |  | -+      // specified client-side pointer
 | 
	
		
			
				|  |  | -+      glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW);
 | 
	
		
			
				|  |  | -+      // Set up the offsets of the various vertex attributes within the buffer
 | 
	
		
			
				|  |  | -+      // object bound to GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+      glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
 | 
	
		
			
				|  |  | -+      glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
 | 
	
		
			
				|  |  | -+      glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+      // Do the actual drawing operation, using the full set of vertices in the buffer
 | 
	
		
			
				|  |  | -       glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
 | 
	
		
			
				|  |  | -+      // Release the buffer name for reuse
 | 
	
		
			
				|  |  | -+      glDeleteBuffers(1, &vertexBuffer);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       g_matrices.PopMatrix();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -@@ -220,6 +232,8 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -     g_graphicsContext.ResetScissors();
 | 
	
		
			
				|  |  | -     // Restore the original model view matrix
 | 
	
		
			
				|  |  | -     glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | -+    // Unbind GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+    glBindBuffer(GL_ARRAY_BUFFER, 0);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Disable the attributes used by this shader
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 3c6c1c4f9c7aec0f41fd22d7d4e7f5918a70c69a Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 15 Jan 2014 16:04:04 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 30/94] Move vertex data into an OpenGL VBO when the font cache
 | 
	
		
			
				|  |  | - entry is populated. The font cache now stores the "name" (handle) of the VBO,
 | 
	
		
			
				|  |  | - rather than a vector of vertices.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontCache.cpp |  6 ++++
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontCache.h   | 30 +++++++++++++++++-
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.cpp   | 15 +++++++--
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTF.h     |  7 +++--
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp | 74 ++++++++++++++++++++++++++++++--------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.h   |  5 +++
 | 
	
		
			
				|  |  | - 6 files changed, 107 insertions(+), 30 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -index b66c00b..895fa72 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -@@ -111,3 +111,9 @@ template void CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDyna
 | 
	
		
			
				|  |  | - template CGUIFontCacheEntry<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::~CGUIFontCacheEntry();
 | 
	
		
			
				|  |  | - template CGUIFontCacheDynamicValue &CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Lookup(CGUIFontCacheDynamicPosition &, const vecColors &, const vecText &, uint32_t, float, bool, unsigned int, bool &);
 | 
	
		
			
				|  |  | - template void CGUIFontCache<CGUIFontCacheDynamicPosition, CGUIFontCacheDynamicValue>::Flush();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CVertexBuffer::clear()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (m_font != NULL)
 | 
	
		
			
				|  |  | -+    m_font->DestroyVertexBuffer(*this);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontCache.h b/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -index d913dee..ff766bf 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontCache.h
 | 
	
		
			
				|  |  | -@@ -234,7 +234,35 @@ struct CGUIFontCacheDynamicPosition
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --typedef std::vector<SVertex> CGUIFontCacheDynamicValue;
 | 
	
		
			
				|  |  | -+struct CVertexBuffer
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  void *bufferHandle;
 | 
	
		
			
				|  |  | -+  size_t size;
 | 
	
		
			
				|  |  | -+  CVertexBuffer() : bufferHandle(NULL), size(0), m_font(NULL) {}
 | 
	
		
			
				|  |  | -+  CVertexBuffer(void *bufferHandle, size_t size, const CGUIFontTTFBase *font) : bufferHandle(bufferHandle), size(size), m_font(font) {}
 | 
	
		
			
				|  |  | -+  CVertexBuffer(const CVertexBuffer &other) : bufferHandle(other.bufferHandle), size(other.size), m_font(other.m_font)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    /* In practice, the copy constructor is only called before a vertex buffer
 | 
	
		
			
				|  |  | -+     * has been attached. If this should ever change, we'll need another support
 | 
	
		
			
				|  |  | -+     * function in GUIFontTTFGL/DX to duplicate a buffer, given its handle. */
 | 
	
		
			
				|  |  | -+    assert(other.bufferHandle == 0);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  CVertexBuffer &operator=(CVertexBuffer &other)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    /* This is used with move-assignment semantics for initialising the object in the font cache */
 | 
	
		
			
				|  |  | -+    assert(bufferHandle == 0);
 | 
	
		
			
				|  |  | -+    bufferHandle = other.bufferHandle;
 | 
	
		
			
				|  |  | -+    other.bufferHandle = 0;
 | 
	
		
			
				|  |  | -+    size = other.size;
 | 
	
		
			
				|  |  | -+    m_font = other.m_font;
 | 
	
		
			
				|  |  | -+    return *this;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  void clear();
 | 
	
		
			
				|  |  | -+private:
 | 
	
		
			
				|  |  | -+  const CGUIFontTTFBase *m_font;
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+typedef CVertexBuffer CGUIFontCacheDynamicValue;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - inline bool Match(const CGUIFontCacheDynamicPosition &a, const TransformMatrix &a_m,
 | 
	
		
			
				|  |  | -                   const CGUIFontCacheDynamicPosition &b, const TransformMatrix &b_m,
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.cpp b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -index 4dc4c8e..8b25306 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.cpp
 | 
	
		
			
				|  |  | -@@ -343,13 +343,18 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | -                                               g_graphicsContext.ScaleFinalYCoord(x, y),
 | 
	
		
			
				|  |  | -                                               g_graphicsContext.ScaleFinalZCoord(x, y));
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  std::vector<SVertex> &vertices = hardwareClipping ?
 | 
	
		
			
				|  |  | -+  CVertexBuffer unusedVertexBuffer;
 | 
	
		
			
				|  |  | -+  CVertexBuffer &vertexBuffer = hardwareClipping ?
 | 
	
		
			
				|  |  | -       m_dynamicCache.Lookup(dynamicPos,
 | 
	
		
			
				|  |  | -                             colors, text,
 | 
	
		
			
				|  |  | -                             alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | -                             scrolling,
 | 
	
		
			
				|  |  | -                             XbmcThreads::SystemClockMillis(),
 | 
	
		
			
				|  |  | -                             dirtyCache) :
 | 
	
		
			
				|  |  | -+      unusedVertexBuffer;
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> tempVertices;
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> &vertices = hardwareClipping ?
 | 
	
		
			
				|  |  | -+      tempVertices :
 | 
	
		
			
				|  |  | -       m_staticCache.Lookup(staticPos,
 | 
	
		
			
				|  |  | -                            colors, text,
 | 
	
		
			
				|  |  | -                            alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | -@@ -459,10 +464,14 @@ void CGUIFontTTFBase::DrawTextInternal(float x, float y, const vecColors &colors
 | 
	
		
			
				|  |  | -         cursorX += ch->advance;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     if (hardwareClipping)
 | 
	
		
			
				|  |  | --      m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertices, g_graphicsContext.GetClipRegion()));
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CVertexBuffer newVertexBuffer = CreateVertexBuffer(tempVertices);
 | 
	
		
			
				|  |  | -+      vertexBuffer = newVertexBuffer;
 | 
	
		
			
				|  |  | -+      m_vertexTrans.push_back(CTranslatedVertices(0, 0, 0, &vertexBuffer, g_graphicsContext.GetClipRegion()));
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   else if (hardwareClipping)
 | 
	
		
			
				|  |  | --    m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertices, g_graphicsContext.GetClipRegion()));
 | 
	
		
			
				|  |  | -+    m_vertexTrans.push_back(CTranslatedVertices(dynamicPos.m_x, dynamicPos.m_y, dynamicPos.m_z, &vertexBuffer, g_graphicsContext.GetClipRegion()));
 | 
	
		
			
				|  |  | -   if (!hardwareClipping)
 | 
	
		
			
				|  |  | -     /* Append the new vertices (from the cache or otherwise) to the set collected
 | 
	
		
			
				|  |  | -      * since the first Begin() call */
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTF.h b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -index 5e7c31f..b1cd525 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTF.h
 | 
	
		
			
				|  |  | -@@ -84,6 +84,9 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   void Begin();
 | 
	
		
			
				|  |  | -   void End();
 | 
	
		
			
				|  |  | -+  /* The next two should only be called if we've declared we can do hardware clipping */
 | 
	
		
			
				|  |  | -+  virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const { assert(false); return CVertexBuffer(); }
 | 
	
		
			
				|  |  | -+  virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const {}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   const CStdString& GetFileName() const { return m_strFileName; };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -167,9 +170,9 @@ class CGUIFontTTFBase
 | 
	
		
			
				|  |  | -     float translateX;
 | 
	
		
			
				|  |  | -     float translateY;
 | 
	
		
			
				|  |  | -     float translateZ;
 | 
	
		
			
				|  |  | --    const std::vector<SVertex> *vertexBuffer;
 | 
	
		
			
				|  |  | -+    const CVertexBuffer *vertexBuffer;
 | 
	
		
			
				|  |  | -     CRect clip;
 | 
	
		
			
				|  |  | --    CTranslatedVertices(float translateX, float translateY, float translateZ, const std::vector<SVertex> *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
 | 
	
		
			
				|  |  | -+    CTranslatedVertices(float translateX, float translateY, float translateZ, const CVertexBuffer *vertexBuffer, const CRect &clip) : translateX(translateX), translateY(translateY), translateZ(translateZ), vertexBuffer(vertexBuffer), clip(clip) {}
 | 
	
		
			
				|  |  | -   };
 | 
	
		
			
				|  |  | -   std::vector<CTranslatedVertices> m_vertexTrans;
 | 
	
		
			
				|  |  | -   std::vector<SVertex> m_vertex;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index 0df3749..1cd684b7 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -49,6 +49,10 @@ CGUIFontTTFGL::CGUIFontTTFGL(const CStdString& strFileName)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - CGUIFontTTFGL::~CGUIFontTTFGL(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+  // It's important that all the CGUIFontCacheEntry objects are
 | 
	
		
			
				|  |  | -+  // destructed before the CGUIFontTTFGL goes out of scope, because
 | 
	
		
			
				|  |  | -+  // our virtual methods won't be accessible after this point
 | 
	
		
			
				|  |  | -+  m_dynamicCache.Flush();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool CGUIFontTTFGL::FirstBegin()
 | 
	
		
			
				|  |  | -@@ -182,7 +186,6 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -   if (m_vertexTrans.size() > 0)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     // Deal with the vertices that can be hardware clipped and therefore translated
 | 
	
		
			
				|  |  | --    std::vector<SVertex> vecVertices;
 | 
	
		
			
				|  |  | -     for (size_t i = 0; i < m_vertexTrans.size(); i++)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       // Apply the clip rectangle
 | 
	
		
			
				|  |  | -@@ -195,36 +198,17 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -       g_matrices.Translatef(m_vertexTrans[i].translateX, m_vertexTrans[i].translateY, m_vertexTrans[i].translateZ);
 | 
	
		
			
				|  |  | -       glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      vecVertices.clear();
 | 
	
		
			
				|  |  | --      for (size_t j = 0; j < m_vertexTrans[i].vertexBuffer->size(); j += 4)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j]);
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+1]);
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+3]);
 | 
	
		
			
				|  |  | --        vecVertices.push_back((*m_vertexTrans[i].vertexBuffer)[j+2]);
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --      SVertex *vertices = &vecVertices[0];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      // Generate a unique buffer object name and put it in vertexBuffer
 | 
	
		
			
				|  |  | --      GLuint vertexBuffer;
 | 
	
		
			
				|  |  | --      glGenBuffers(1, &vertexBuffer);
 | 
	
		
			
				|  |  | -       // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
 | 
	
		
			
				|  |  | --      glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
 | 
	
		
			
				|  |  | --      // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | --      // binding point (i.e. our buffer object) and initialise it from the
 | 
	
		
			
				|  |  | --      // specified client-side pointer
 | 
	
		
			
				|  |  | --      glBufferData(GL_ARRAY_BUFFER, vecVertices.size() * sizeof *vertices, vertices, GL_STATIC_DRAW);
 | 
	
		
			
				|  |  | -+      glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -       // Set up the offsets of the various vertex attributes within the buffer
 | 
	
		
			
				|  |  | -       // object bound to GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -       glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
 | 
	
		
			
				|  |  | -       glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
 | 
	
		
			
				|  |  | -       glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -       // Do the actual drawing operation, using the full set of vertices in the buffer
 | 
	
		
			
				|  |  | --      glDrawArrays(GL_TRIANGLES, 0, vecVertices.size());
 | 
	
		
			
				|  |  | --      // Release the buffer name for reuse
 | 
	
		
			
				|  |  | --      glDeleteBuffers(1, &vertexBuffer);
 | 
	
		
			
				|  |  | -+      glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       g_matrices.PopMatrix();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -@@ -245,6 +229,48 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vertices) const
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  // Rearrange the vertices to describe triangles
 | 
	
		
			
				|  |  | -+  std::vector<SVertex> triangleVertices;
 | 
	
		
			
				|  |  | -+  triangleVertices.reserve(vertices.size() * 6 / 4);
 | 
	
		
			
				|  |  | -+  for (size_t i = 0; i < vertices.size(); i += 4)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    triangleVertices.push_back(vertices[i]);
 | 
	
		
			
				|  |  | -+    triangleVertices.push_back(vertices[i+1]);
 | 
	
		
			
				|  |  | -+    triangleVertices.push_back(vertices[i+2]);
 | 
	
		
			
				|  |  | -+    triangleVertices.push_back(vertices[i+1]);
 | 
	
		
			
				|  |  | -+    triangleVertices.push_back(vertices[i+3]);
 | 
	
		
			
				|  |  | -+    triangleVertices.push_back(vertices[i+2]);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // Generate a unique buffer object name and put it in bufferHandle
 | 
	
		
			
				|  |  | -+  GLuint bufferHandle;
 | 
	
		
			
				|  |  | -+  glGenBuffers(1, &bufferHandle);
 | 
	
		
			
				|  |  | -+  // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
 | 
	
		
			
				|  |  | -+  glBindBuffer(GL_ARRAY_BUFFER, bufferHandle);
 | 
	
		
			
				|  |  | -+  // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+  // binding point (i.e. our buffer object) and initialise it from the
 | 
	
		
			
				|  |  | -+  // specified client-side pointer
 | 
	
		
			
				|  |  | -+  glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW);
 | 
	
		
			
				|  |  | -+  // Unbind GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+  glBindBuffer(GL_ARRAY_BUFFER, 0);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return CVertexBuffer((void *) bufferHandle, vertices.size() / 4, this);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CGUIFontTTFGL::DestroyVertexBuffer(CVertexBuffer &buffer) const
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  if (buffer.bufferHandle != 0)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    // Release the buffer name for reuse
 | 
	
		
			
				|  |  | -+    glDeleteBuffers(1, (GLuint *) &buffer.bufferHandle);
 | 
	
		
			
				|  |  | -+    buffer.bufferHandle = 0;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - CBaseTexture* CGUIFontTTFGL::ReallocTexture(unsigned int& newHeight)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   newHeight = CBaseTexture::PadPow2(newHeight);
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -index 6736cf7..168fb21 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -@@ -29,6 +29,7 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "GUIFontTTF.h"
 | 
	
		
			
				|  |  | -+#include "system.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - /*!
 | 
	
		
			
				|  |  | -@@ -43,6 +44,10 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   virtual bool FirstBegin();
 | 
	
		
			
				|  |  | -   virtual void LastEnd();
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+  virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const;
 | 
	
		
			
				|  |  | -+  virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   virtual CBaseTexture* ReallocTexture(unsigned int& newHeight);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 073c09ba7de6f6b7676c83d71b6933790626874f Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Thu, 16 Jan 2014 16:29:42 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 31/94] Switch from glDrawArrays() to glDrawElements(). This
 | 
	
		
			
				|  |  | - involves setting up a static VBO containing the indexes necessary to convert
 | 
	
		
			
				|  |  | - from quads to triangles on the fly in the GPU.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp        | 72 +++++++++++++++++++++++++------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.h          |  9 +++++
 | 
	
		
			
				|  |  | - xbmc/windowing/egl/WinSystemEGL.cpp | 17 +++++++++
 | 
	
		
			
				|  |  | - 3 files changed, 76 insertions(+), 22 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index 1cd684b7..d476409 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -186,6 +186,10 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -   if (m_vertexTrans.size() > 0)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     // Deal with the vertices that can be hardware clipped and therefore translated
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    // Bind our pre-calculated array to GL_ELEMENT_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     for (size_t i = 0; i < m_vertexTrans.size(); i++)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       // Apply the clip rectangle
 | 
	
		
			
				|  |  | -@@ -201,14 +205,21 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -       // Bind the buffer to the OpenGL context's GL_ARRAY_BUFFER binding point
 | 
	
		
			
				|  |  | -       glBindBuffer(GL_ARRAY_BUFFER, (GLuint) m_vertexTrans[i].vertexBuffer->bufferHandle);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      // Set up the offsets of the various vertex attributes within the buffer
 | 
	
		
			
				|  |  | --      // object bound to GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | --      glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, x));
 | 
	
		
			
				|  |  | --      glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(SVertex), (GLvoid *) offsetof(SVertex, r));
 | 
	
		
			
				|  |  | --      glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) offsetof(SVertex, u));
 | 
	
		
			
				|  |  | -+      // Do the actual drawing operation, split into groups of characters no
 | 
	
		
			
				|  |  | -+      // larger than the pre-determined size of the element array
 | 
	
		
			
				|  |  | -+      for (size_t character = 0; m_vertexTrans[i].vertexBuffer->size > character; character += ELEMENT_ARRAY_MAX_CHAR_INDEX)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        size_t count = m_vertexTrans[i].vertexBuffer->size - character;
 | 
	
		
			
				|  |  | -+        count = std::min<size_t>(count, ELEMENT_ARRAY_MAX_CHAR_INDEX);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+        // Set up the offsets of the various vertex attributes within the buffer
 | 
	
		
			
				|  |  | -+        // object bound to GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+        glVertexAttribPointer(posLoc,  3, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, x)));
 | 
	
		
			
				|  |  | -+        glVertexAttribPointer(colLoc,  4, GL_UNSIGNED_BYTE, GL_TRUE,  sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, r)));
 | 
	
		
			
				|  |  | -+        glVertexAttribPointer(tex0Loc, 2, GL_FLOAT,         GL_FALSE, sizeof(SVertex), (GLvoid *) (character*sizeof(SVertex)*4 + offsetof(SVertex, u)));
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      // Do the actual drawing operation, using the full set of vertices in the buffer
 | 
	
		
			
				|  |  | --      glDrawArrays(GL_TRIANGLES, 0, 6 * m_vertexTrans[i].vertexBuffer->size);
 | 
	
		
			
				|  |  | -+        glDrawElements(GL_TRIANGLES, 6 * count, GL_UNSIGNED_SHORT, 0);
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       g_matrices.PopMatrix();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -@@ -216,8 +227,9 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -     g_graphicsContext.ResetScissors();
 | 
	
		
			
				|  |  | -     // Restore the original model view matrix
 | 
	
		
			
				|  |  | -     glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | --    // Unbind GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -+    // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -     glBindBuffer(GL_ARRAY_BUFFER, 0);
 | 
	
		
			
				|  |  | -+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Disable the attributes used by this shader
 | 
	
		
			
				|  |  | -@@ -232,19 +244,6 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | - #if HAS_GLES
 | 
	
		
			
				|  |  | - CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vertices) const
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  // Rearrange the vertices to describe triangles
 | 
	
		
			
				|  |  | --  std::vector<SVertex> triangleVertices;
 | 
	
		
			
				|  |  | --  triangleVertices.reserve(vertices.size() * 6 / 4);
 | 
	
		
			
				|  |  | --  for (size_t i = 0; i < vertices.size(); i += 4)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    triangleVertices.push_back(vertices[i]);
 | 
	
		
			
				|  |  | --    triangleVertices.push_back(vertices[i+1]);
 | 
	
		
			
				|  |  | --    triangleVertices.push_back(vertices[i+2]);
 | 
	
		
			
				|  |  | --    triangleVertices.push_back(vertices[i+1]);
 | 
	
		
			
				|  |  | --    triangleVertices.push_back(vertices[i+3]);
 | 
	
		
			
				|  |  | --    triangleVertices.push_back(vertices[i+2]);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   // Generate a unique buffer object name and put it in bufferHandle
 | 
	
		
			
				|  |  | -   GLuint bufferHandle;
 | 
	
		
			
				|  |  | -   glGenBuffers(1, &bufferHandle);
 | 
	
		
			
				|  |  | -@@ -253,7 +252,7 @@ CVertexBuffer CGUIFontTTFGL::CreateVertexBuffer(const std::vector<SVertex> &vert
 | 
	
		
			
				|  |  | -   // Create a data store for the buffer object bound to the GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -   // binding point (i.e. our buffer object) and initialise it from the
 | 
	
		
			
				|  |  | -   // specified client-side pointer
 | 
	
		
			
				|  |  | --  glBufferData(GL_ARRAY_BUFFER, triangleVertices.size() * sizeof (SVertex), &triangleVertices[0], GL_STATIC_DRAW);
 | 
	
		
			
				|  |  | -+  glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof (SVertex), &vertices[0], GL_STATIC_DRAW);
 | 
	
		
			
				|  |  | -   // Unbind GL_ARRAY_BUFFER
 | 
	
		
			
				|  |  | -   glBindBuffer(GL_ARRAY_BUFFER, 0);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -348,4 +347,33 @@ void CGUIFontTTFGL::DeleteHardwareTexture()
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+void CGUIFontTTFGL::CreateStaticVertexBuffers(void)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  // Bind a new buffer to the OpenGL context's GL_ELEMENT_ARRAY_BUFFER binding point
 | 
	
		
			
				|  |  | -+  glGenBuffers(1, &m_elementArrayHandle);
 | 
	
		
			
				|  |  | -+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementArrayHandle);
 | 
	
		
			
				|  |  | -+  // Create an array holding the mesh indices to convert quads to triangles
 | 
	
		
			
				|  |  | -+  GLushort index[ELEMENT_ARRAY_MAX_CHAR_INDEX][6];
 | 
	
		
			
				|  |  | -+  for (size_t i = 0; i < ELEMENT_ARRAY_MAX_CHAR_INDEX; i++)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    index[i][0] = 4*i;
 | 
	
		
			
				|  |  | -+    index[i][1] = 4*i+1;
 | 
	
		
			
				|  |  | -+    index[i][2] = 4*i+2;
 | 
	
		
			
				|  |  | -+    index[i][3] = 4*i+1;
 | 
	
		
			
				|  |  | -+    index[i][4] = 4*i+3;
 | 
	
		
			
				|  |  | -+    index[i][5] = 4*i+2;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof index, index, GL_STATIC_DRAW);
 | 
	
		
			
				|  |  | -+  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CGUIFontTTFGL::DestroyStaticVertexBuffers(void)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  glDeleteBuffers(1, &m_elementArrayHandle);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+GLuint CGUIFontTTFGL::m_elementArrayHandle;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.h b/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -index 168fb21..a14ab7a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.h
 | 
	
		
			
				|  |  | -@@ -30,6 +30,7 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "GUIFontTTF.h"
 | 
	
		
			
				|  |  | - #include "system.h"
 | 
	
		
			
				|  |  | -+#include "system_gl.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - /*!
 | 
	
		
			
				|  |  | -@@ -47,6 +48,8 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
 | 
	
		
			
				|  |  | - #if HAS_GLES
 | 
	
		
			
				|  |  | -   virtual CVertexBuffer CreateVertexBuffer(const std::vector<SVertex> &vertices) const;
 | 
	
		
			
				|  |  | -   virtual void DestroyVertexBuffer(CVertexBuffer &bufferHandle) const;
 | 
	
		
			
				|  |  | -+  static void CreateStaticVertexBuffers(void);
 | 
	
		
			
				|  |  | -+  static void DestroyStaticVertexBuffers(void);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -@@ -54,6 +57,12 @@ class CGUIFontTTFGL : public CGUIFontTTFBase
 | 
	
		
			
				|  |  | -   virtual bool CopyCharToTexture(FT_BitmapGlyph bitGlyph, unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2);
 | 
	
		
			
				|  |  | -   virtual void DeleteHardwareTexture();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+#define ELEMENT_ARRAY_MAX_CHAR_INDEX (1000)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  static GLuint m_elementArrayHandle;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
 | 
	
		
			
				|  |  | -index dfc4672..0c32947 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/windowing/egl/WinSystemEGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/windowing/egl/WinSystemEGL.cpp
 | 
	
		
			
				|  |  | -@@ -29,6 +29,7 @@
 | 
	
		
			
				|  |  | - #include "settings/AdvancedSettings.h"
 | 
	
		
			
				|  |  | - #include "settings/Settings.h"
 | 
	
		
			
				|  |  | - #include "settings/DisplaySettings.h"
 | 
	
		
			
				|  |  | -+#include "guilib/GUIFontTTFGL.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - #include "EGLWrapper.h"
 | 
	
		
			
				|  |  | - #include "EGLQuirks.h"
 | 
	
		
			
				|  |  | -@@ -192,6 +193,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+  bool newContext = false;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   if (m_context == EGL_NO_CONTEXT)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     if (!m_egl->CreateContext(m_display, m_config, contextAttrs, &m_context))
 | 
	
		
			
				|  |  | -@@ -199,6 +203,9 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
 | 
	
		
			
				|  |  | -       CLog::Log(LOGERROR, "%s: Could not create context",__FUNCTION__);
 | 
	
		
			
				|  |  | -       return false;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+    newContext = true;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (!m_egl->BindContext(m_display, m_surface, m_context))
 | 
	
		
			
				|  |  | -@@ -207,6 +214,11 @@ bool CWinSystemEGL::CreateWindow(RESOLUTION_INFO &res)
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+  if (newContext)
 | 
	
		
			
				|  |  | -+    CGUIFontTTFGL::CreateStaticVertexBuffers();
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // for the non-trivial dirty region modes, we need the EGL buffer to be preserved across updates
 | 
	
		
			
				|  |  | -   if (g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_COST_REDUCTION ||
 | 
	
		
			
				|  |  | -       g_advancedSettings.m_guiAlgorithmDirtyRegions == DIRTYREGION_SOLVER_UNION)
 | 
	
		
			
				|  |  | -@@ -228,7 +240,12 @@ bool CWinSystemEGL::DestroyWindowSystem()
 | 
	
		
			
				|  |  | -   DestroyWindow();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (m_context != EGL_NO_CONTEXT)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+#if HAS_GLES
 | 
	
		
			
				|  |  | -+    CGUIFontTTFGL::DestroyStaticVertexBuffers();
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -     m_egl->DestroyContext(m_display, m_context);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   m_context = EGL_NO_CONTEXT;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (m_display != EGL_NO_DISPLAY)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From ec39dce3628b276e3ed2fe19c95a056a1aa171b8 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Tue, 4 Feb 2014 16:17:57 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 32/94] Update Windows project files
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - project/VS2010Express/XBMC.vcxproj         | 2 ++
 | 
	
		
			
				|  |  | - project/VS2010Express/XBMC.vcxproj.filters | 6 ++++++
 | 
	
		
			
				|  |  | - 2 files changed, 8 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
 | 
	
		
			
				|  |  | -index c6de5ca..a9731de 100644
 | 
	
		
			
				|  |  | ---- a/project/VS2010Express/XBMC.vcxproj
 | 
	
		
			
				|  |  | -+++ b/project/VS2010Express/XBMC.vcxproj
 | 
	
		
			
				|  |  | -@@ -540,6 +540,7 @@
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFadeLabelControl.cpp" />
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFixedListContainer.cpp" />
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp" />
 | 
	
		
			
				|  |  | -+    <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp" />
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp" />
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFontTTF.cpp" />
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFontTTFDX.cpp" />
 | 
	
		
			
				|  |  | -@@ -2057,6 +2058,7 @@
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFadeLabelControl.h" />
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFixedListContainer.h" />
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFont.h" />
 | 
	
		
			
				|  |  | -+    <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h" />
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h" />
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFontTTF.h" />
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFontTTFDX.h" />
 | 
	
		
			
				|  |  | -diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
 | 
	
		
			
				|  |  | -index b536eb3..cb34443 100644
 | 
	
		
			
				|  |  | ---- a/project/VS2010Express/XBMC.vcxproj.filters
 | 
	
		
			
				|  |  | -+++ b/project/VS2010Express/XBMC.vcxproj.filters
 | 
	
		
			
				|  |  | -@@ -1024,6 +1024,9 @@
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFont.cpp">
 | 
	
		
			
				|  |  | -       <Filter>guilib</Filter>
 | 
	
		
			
				|  |  | -     </ClCompile>
 | 
	
		
			
				|  |  | -+    <ClCompile Include="..\..\xbmc\guilib\GUIFontCache.cpp">
 | 
	
		
			
				|  |  | -+      <Filter>guilib</Filter>
 | 
	
		
			
				|  |  | -+    </ClCompile>
 | 
	
		
			
				|  |  | -     <ClCompile Include="..\..\xbmc\guilib\GUIFontManager.cpp">
 | 
	
		
			
				|  |  | -       <Filter>guilib</Filter>
 | 
	
		
			
				|  |  | -     </ClCompile>
 | 
	
		
			
				|  |  | -@@ -3978,6 +3981,9 @@
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFont.h">
 | 
	
		
			
				|  |  | -       <Filter>guilib</Filter>
 | 
	
		
			
				|  |  | -     </ClInclude>
 | 
	
		
			
				|  |  | -+    <ClInclude Include="..\..\xbmc\guilib\GUIFontCache.h">
 | 
	
		
			
				|  |  | -+      <Filter>guilib</Filter>
 | 
	
		
			
				|  |  | -+    </ClInclude>
 | 
	
		
			
				|  |  | -     <ClInclude Include="..\..\xbmc\guilib\GUIFontManager.h">
 | 
	
		
			
				|  |  | -       <Filter>guilib</Filter>
 | 
	
		
			
				|  |  | -     </ClInclude>
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From e25eb385d09a5378be8616f10806610df90416db Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Tue, 4 Feb 2014 16:49:45 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 33/94] Update XCode project file
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - XBMC.xcodeproj/project.pbxproj | 10 ++++++++++
 | 
	
		
			
				|  |  | - 1 file changed, 10 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/XBMC.xcodeproj/project.pbxproj b/XBMC.xcodeproj/project.pbxproj
 | 
	
		
			
				|  |  | -index fdd10a1..62e7e69 100644
 | 
	
		
			
				|  |  | ---- a/XBMC.xcodeproj/project.pbxproj
 | 
	
		
			
				|  |  | -+++ b/XBMC.xcodeproj/project.pbxproj
 | 
	
		
			
				|  |  | -@@ -168,6 +168,9 @@
 | 
	
		
			
				|  |  | - 		1D638128161E211E003603ED /* PeripheralImon.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1D638126161E211E003603ED /* PeripheralImon.cpp */; };
 | 
	
		
			
				|  |  | - 		1DAFDB7C16DFDCA7007F8C68 /* PeripheralBusCEC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DAFDB7A16DFDCA7007F8C68 /* PeripheralBusCEC.cpp */; };
 | 
	
		
			
				|  |  | - 		1DE0443515828F4B005DDB4D /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1DE0443315828F4B005DDB4D /* Exception.cpp */; };
 | 
	
		
			
				|  |  | -+		2FD7EC5F18A14FE50047F86C /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */; };
 | 
	
		
			
				|  |  | -+		2FD7EC6018A14FE50047F86C /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */; };
 | 
	
		
			
				|  |  | -+		2FD7EC6118A14FE50047F86C /* GUIFontCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */; };
 | 
	
		
			
				|  |  | - 		32C631281423A90F00F18420 /* JpegIO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 32C631261423A90F00F18420 /* JpegIO.cpp */; };
 | 
	
		
			
				|  |  | - 		36A9443D15821E2800727135 /* DatabaseUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443B15821E2800727135 /* DatabaseUtils.cpp */; };
 | 
	
		
			
				|  |  | - 		36A9444115821E7C00727135 /* SortUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A9443F15821E7C00727135 /* SortUtils.cpp */; };
 | 
	
		
			
				|  |  | -@@ -3546,6 +3549,8 @@
 | 
	
		
			
				|  |  | - 		1DAFDB7B16DFDCA7007F8C68 /* PeripheralBusCEC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PeripheralBusCEC.h; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | - 		1DE0443315828F4B005DDB4D /* Exception.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Exception.cpp; path = commons/Exception.cpp; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | - 		1DE0443415828F4B005DDB4D /* Exception.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Exception.h; path = commons/Exception.h; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | -+		2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIFontCache.cpp; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | -+		2FD7EC5E18A14FE50047F86C /* GUIFontCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIFontCache.h; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | - 		32C631261423A90F00F18420 /* JpegIO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JpegIO.cpp; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | - 		32C631271423A90F00F18420 /* JpegIO.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JpegIO.h; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | - 		36A9443B15821E2800727135 /* DatabaseUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DatabaseUtils.cpp; sourceTree = "<group>"; };
 | 
	
		
			
				|  |  | -@@ -5923,6 +5928,8 @@
 | 
	
		
			
				|  |  | - 				18B7C76A1294222E009E7A26 /* GUIFixedListContainer.cpp */,
 | 
	
		
			
				|  |  | - 				18B7C7101294222D009E7A26 /* GUIFixedListContainer.h */,
 | 
	
		
			
				|  |  | - 				18B7C76B1294222E009E7A26 /* GUIFont.cpp */,
 | 
	
		
			
				|  |  | -+				2FD7EC5D18A14FE50047F86C /* GUIFontCache.cpp */,
 | 
	
		
			
				|  |  | -+				2FD7EC5E18A14FE50047F86C /* GUIFontCache.h */,
 | 
	
		
			
				|  |  | - 				18B7C7111294222D009E7A26 /* GUIFont.h */,
 | 
	
		
			
				|  |  | - 				18B7C76C1294222E009E7A26 /* GUIFontManager.cpp */,
 | 
	
		
			
				|  |  | - 				18B7C7121294222D009E7A26 /* GUIFontManager.h */,
 | 
	
		
			
				|  |  | -@@ -10930,6 +10937,7 @@
 | 
	
		
			
				|  |  | - 				7C8AE850189DE3CD00C33786 /* CoreAudioHardware.cpp in Sources */,
 | 
	
		
			
				|  |  | - 				7C8AE851189DE3CD00C33786 /* CoreAudioStream.cpp in Sources */,
 | 
	
		
			
				|  |  | - 				7C8AE854189DE47F00C33786 /* CoreAudioHelpers.cpp in Sources */,
 | 
	
		
			
				|  |  | -+				2FD7EC5F18A14FE50047F86C /* GUIFontCache.cpp in Sources */,
 | 
	
		
			
				|  |  | - 			);
 | 
	
		
			
				|  |  | - 			runOnlyForDeploymentPostprocessing = 0;
 | 
	
		
			
				|  |  | - 		};
 | 
	
		
			
				|  |  | -@@ -11978,6 +11986,7 @@
 | 
	
		
			
				|  |  | - 				F5CC234818150277006B5E91 /* AESinkNULL.cpp in Sources */,
 | 
	
		
			
				|  |  | - 				F5CC238918150768006B5E91 /* AESinkProfiler.cpp in Sources */,
 | 
	
		
			
				|  |  | - 				DF374B2518AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */,
 | 
	
		
			
				|  |  | -+				2FD7EC6118A14FE50047F86C /* GUIFontCache.cpp in Sources */,
 | 
	
		
			
				|  |  | - 			);
 | 
	
		
			
				|  |  | - 			runOnlyForDeploymentPostprocessing = 0;
 | 
	
		
			
				|  |  | - 		};
 | 
	
		
			
				|  |  | -@@ -13028,6 +13037,7 @@
 | 
	
		
			
				|  |  | - 				F5CC234718150277006B5E91 /* AESinkNULL.cpp in Sources */,
 | 
	
		
			
				|  |  | - 				F5CC238818150768006B5E91 /* AESinkProfiler.cpp in Sources */,
 | 
	
		
			
				|  |  | - 				DF374B2418AC2BA20076B514 /* CoreAudioHelpers.cpp in Sources */,
 | 
	
		
			
				|  |  | -+				2FD7EC6018A14FE50047F86C /* GUIFontCache.cpp in Sources */,
 | 
	
		
			
				|  |  | - 			);
 | 
	
		
			
				|  |  | - 			runOnlyForDeploymentPostprocessing = 0;
 | 
	
		
			
				|  |  | - 		};
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 5f4ebd2e9fd6d503220627b916e522b671d7d9ba Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Tue, 4 Feb 2014 17:44:34 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 34/94] Clang seems to be more picky than gcc about some C++
 | 
	
		
			
				|  |  | - template syntax
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontCache.cpp | 20 ++++++++++----------
 | 
	
		
			
				|  |  | - 1 file changed, 10 insertions(+), 10 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontCache.cpp b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -index 895fa72..bd84b9a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontCache.cpp
 | 
	
		
			
				|  |  | -@@ -61,26 +61,26 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
 | 
	
		
			
				|  |  | -                                        alignment, maxPixelWidth,
 | 
	
		
			
				|  |  | -                                        scrolling, g_graphicsContext.GetGUIMatrix(),
 | 
	
		
			
				|  |  | -                                        g_graphicsContext.GetGUIScaleX(), g_graphicsContext.GetGUIScaleY());
 | 
	
		
			
				|  |  | --  EntryHashIterator i = m_list.get<Hash>().find(key);
 | 
	
		
			
				|  |  | --  if (i == m_list.get<Hash>().end())
 | 
	
		
			
				|  |  | -+  EntryHashIterator i = m_list.template get<Hash>().find(key);
 | 
	
		
			
				|  |  | -+  if (i == m_list.template get<Hash>().end())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     /* Cache miss */
 | 
	
		
			
				|  |  | --    EntryAgeIterator oldest = m_list.get<Age>().begin();
 | 
	
		
			
				|  |  | --    if (!m_list.get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
 | 
	
		
			
				|  |  | -+    EntryAgeIterator oldest = m_list.template get<Age>().begin();
 | 
	
		
			
				|  |  | -+    if (!m_list.template get<Age>().empty() && nowMillis - oldest->m_lastUsedMillis > FONT_CACHE_TIME_LIMIT)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       /* The oldest existing entry is old enough to expire and reuse */
 | 
	
		
			
				|  |  | --      m_list.get<Hash>().modify(m_list.project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
 | 
	
		
			
				|  |  | --      m_list.get<Age>().relocate(m_list.get<Age>().end(), oldest);
 | 
	
		
			
				|  |  | -+      m_list.template get<Hash>().modify(m_list.template project<Hash>(oldest), typename CGUIFontCacheEntry<Position, Value>::Reassign(key, nowMillis));
 | 
	
		
			
				|  |  | -+      m_list.template get<Age>().relocate(m_list.template get<Age>().end(), oldest);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     else
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       /* We need a new entry instead */
 | 
	
		
			
				|  |  | -       /* Yes, this causes the creation an destruction of a temporary entry, but
 | 
	
		
			
				|  |  | -        * this code ought to only be used infrequently, when the cache needs to grow */
 | 
	
		
			
				|  |  | --      m_list.get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
 | 
	
		
			
				|  |  | -+      m_list.template get<Age>().push_back(CGUIFontCacheEntry<Position, Value>(*this, key, nowMillis));
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     dirtyCache = true;
 | 
	
		
			
				|  |  | --    return (--m_list.get<Age>().end())->m_value;
 | 
	
		
			
				|  |  | -+    return (--m_list.template get<Age>().end())->m_value;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -90,7 +90,7 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
 | 
	
		
			
				|  |  | -     pos.UpdateWithOffsets(i->m_key.m_pos, scrolling);
 | 
	
		
			
				|  |  | -     /* Update time in entry and move to the back of the list */
 | 
	
		
			
				|  |  | -     i->m_lastUsedMillis = nowMillis;
 | 
	
		
			
				|  |  | --    m_list.get<Age>().relocate(m_list.get<Age>().end(), m_list.project<Age>(i));
 | 
	
		
			
				|  |  | -+    m_list.template get<Age>().relocate(m_list.template get<Age>().end(), m_list.template project<Age>(i));
 | 
	
		
			
				|  |  | -     dirtyCache = false;
 | 
	
		
			
				|  |  | -     return i->m_value;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -@@ -99,7 +99,7 @@ Value &CGUIFontCache<Position, Value>::Lookup(Position &pos,
 | 
	
		
			
				|  |  | - template<class Position, class Value>
 | 
	
		
			
				|  |  | - void CGUIFontCache<Position, Value>::Flush()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  m_list.get<Age>().clear();
 | 
	
		
			
				|  |  | -+  m_list.template get<Age>().clear();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - template void CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue>::Reassign::operator()(CGUIFontCacheEntry<CGUIFontCacheStaticPosition, CGUIFontCacheStaticValue> &entry);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 33693dc9ff9ba7695bc0e702a41566d54a5135b9 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Tue, 4 Feb 2014 18:52:14 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 35/94] Fix header to hopefully permit iOS builds to work
 | 
	
		
			
				|  |  | - again. GUIShader.cpp added #include windowing/egl/WinSystemEGL.h inside a but
 | 
	
		
			
				|  |  | - also need the header windowing/osx/WinSystemIOS.h instead. The only thing
 | 
	
		
			
				|  |  | - GUIShader.cpp needed was g_windowing.GetViewPort, which is provided by the
 | 
	
		
			
				|  |  | - common base class CRenderSystemGLES of g_windowing in both cases, so I think
 | 
	
		
			
				|  |  | - it should be sufficient to use windowing/WindowingFactory.h instead, which is
 | 
	
		
			
				|  |  | - abstracted away from the other header files.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIShader.cpp | 2 +-
 | 
	
		
			
				|  |  | - 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIShader.cpp b/xbmc/guilib/GUIShader.cpp
 | 
	
		
			
				|  |  | -index 53bce09..86330cc 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIShader.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIShader.cpp
 | 
	
		
			
				|  |  | -@@ -26,7 +26,7 @@
 | 
	
		
			
				|  |  | - #include "GUIShader.h"
 | 
	
		
			
				|  |  | - #include "MatrixGLES.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | --#include "windowing/egl/WinSystemEGL.h"
 | 
	
		
			
				|  |  | -+#include "windowing/WindowingFactory.h"
 | 
	
		
			
				|  |  | - #include "guilib/GraphicContext.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - CGUIShader::CGUIShader( const char *shader ) : CGLSLShaderProgram("guishader_vert.glsl", shader)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 9b95b3b13bd714d8320dc61c5039eee6cb3c5737 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Tue, 8 Apr 2014 18:14:55 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 36/94] Fix font display in stereoscopic modes
 | 
	
		
			
				|  |  | - CGUIFontTTFGL::LastEnd was previously using the relatively high-level
 | 
	
		
			
				|  |  | - CGraphicContext::SetScissors function to enforce hardware clipping. However,
 | 
	
		
			
				|  |  | - the coordinates it passed in already contained the stereoscopic offset, so
 | 
	
		
			
				|  |  | - the CGraphicContext::SetScissors effectively ended up double-applying the
 | 
	
		
			
				|  |  | - offset, with the effect that clip rectangles were always off-screen. Changed
 | 
	
		
			
				|  |  | - to call the low-level SetScissors call instead (using g_Windowing to select
 | 
	
		
			
				|  |  | - the correct implementation, e.g. CRenderSystemGLES::SetScissors). This also
 | 
	
		
			
				|  |  | - skips the intersection of the scissors with the screen limits, but that does
 | 
	
		
			
				|  |  | - not appear to matter in practice.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GUIFontTTFGL.cpp | 4 ++--
 | 
	
		
			
				|  |  | - 1 file changed, 2 insertions(+), 2 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GUIFontTTFGL.cpp b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -index d476409..8466a81 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GUIFontTTFGL.cpp
 | 
	
		
			
				|  |  | -@@ -194,7 +194,7 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       // Apply the clip rectangle
 | 
	
		
			
				|  |  | -       CRect clip = g_Windowing.ClipRectToScissorRect(m_vertexTrans[i].clip);
 | 
	
		
			
				|  |  | --      g_graphicsContext.SetScissors(clip);
 | 
	
		
			
				|  |  | -+      g_Windowing.SetScissors(clip);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       // Apply the translation to the currently active (top-of-stack) model view matrix
 | 
	
		
			
				|  |  | -       g_matrices.MatrixMode(MM_MODELVIEW);
 | 
	
		
			
				|  |  | -@@ -224,7 +224,7 @@ void CGUIFontTTFGL::LastEnd()
 | 
	
		
			
				|  |  | -       g_matrices.PopMatrix();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     // Restore the original scissor rectangle
 | 
	
		
			
				|  |  | --    g_graphicsContext.ResetScissors();
 | 
	
		
			
				|  |  | -+    g_Windowing.ResetScissors();
 | 
	
		
			
				|  |  | -     // Restore the original model view matrix
 | 
	
		
			
				|  |  | -     glUniformMatrix4fv(modelLoc, 1, GL_FALSE, g_matrices.GetMatrix(MM_MODELVIEW));
 | 
	
		
			
				|  |  | -     // Unbind GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From d51ef43b61b50de46edb2832f457af8229995cab Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Fri, 10 Jan 2014 12:10:43 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 37/94] [rbp] Don't override dvdplayer with omxplayer.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Using dvdplayer can be useful on the Pi. We can actually play sd (up to 640x480 MPEG-4 video) video in real time.
 | 
	
		
			
				|  |  | -This is useful for codec variants like DivX3 which we don't currently play.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This may expose bugs where dvdplayer is incorrectly used as the default player which will need to be fixed
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/playercorefactory/PlayerCoreConfig.h | 7 -------
 | 
	
		
			
				|  |  | - 1 file changed, 7 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/playercorefactory/PlayerCoreConfig.h b/xbmc/cores/playercorefactory/PlayerCoreConfig.h
 | 
	
		
			
				|  |  | -index 27f0bec..fc12bb7 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/playercorefactory/PlayerCoreConfig.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/playercorefactory/PlayerCoreConfig.h
 | 
	
		
			
				|  |  | -@@ -88,14 +88,7 @@ friend class CPlayerCoreFactory;
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       case EPC_MPLAYER:
 | 
	
		
			
				|  |  | -       // TODO: this hack needs removal until we have a better player selection
 | 
	
		
			
				|  |  | --#if defined(HAS_OMXPLAYER)
 | 
	
		
			
				|  |  | --      case EPC_DVDPLAYER: 
 | 
	
		
			
				|  |  | --        pPlayer = new COMXPlayer(callback); 
 | 
	
		
			
				|  |  | --        CLog::Log(LOGINFO, "Created player %s for core %d / OMXPlayer forced as DVDPlayer", "OMXPlayer", m_eCore);
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --#else
 | 
	
		
			
				|  |  | -       case EPC_DVDPLAYER: pPlayer = new CDVDPlayer(callback); break;
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | -       case EPC_PAPLAYER: pPlayer = new PAPlayer(callback); break;
 | 
	
		
			
				|  |  | -       case EPC_EXTPLAYER: pPlayer = new CExternalPlayer(callback); break;
 | 
	
		
			
				|  |  | - #if defined(HAS_OMXPLAYER)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 3cd01da5418f1693e50ed40273cb17ca9f6d622a Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Fri, 10 Jan 2014 15:37:41 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 38/94] [players] Use default players rather than hard coded
 | 
	
		
			
				|  |  | - DVDPlayer/PAPlayer
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - system/playercorefactory.xml | 23 ++++++++++++-----------
 | 
	
		
			
				|  |  | - 1 file changed, 12 insertions(+), 11 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/system/playercorefactory.xml b/system/playercorefactory.xml
 | 
	
		
			
				|  |  | -index 57dfcdd..7be9799 100644
 | 
	
		
			
				|  |  | ---- a/system/playercorefactory.xml
 | 
	
		
			
				|  |  | -+++ b/system/playercorefactory.xml
 | 
	
		
			
				|  |  | -@@ -11,31 +11,32 @@
 | 
	
		
			
				|  |  | -   </players>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   <rules name="system rules">
 | 
	
		
			
				|  |  | --    <rule name="rtv" protocols="rtv" player="DVDPlayer" />
 | 
	
		
			
				|  |  | --    <rule name="hdhomerun/myth/mms/udp" protocols="hdhomerun|myth|cmyth|mms|mmsh|udp" player="DVDPlayer" />
 | 
	
		
			
				|  |  | --    <rule name="lastfm/shout" protocols="lastfm|shout" player="PAPlayer" />
 | 
	
		
			
				|  |  | -+    <rule name="rtv" protocols="rtv" player="videodefaultplayer" />
 | 
	
		
			
				|  |  | -+    <rule name="hdhomerun/myth/mms/udp" protocols="hdhomerun|myth|cmyth|mms|mmsh|udp" player="videodefaultplayer" />
 | 
	
		
			
				|  |  | -+    <rule name="lastfm/shout" protocols="lastfm|shout" player="audiodefaultplayer" />
 | 
	
		
			
				|  |  | -     <rule name="rtmp" protocols="rtmp" player="videodefaultplayer" />
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     <!-- dvdplayer can play standard rtsp streams -->
 | 
	
		
			
				|  |  | --    <rule name="rtsp" protocols="rtsp" filetypes="!(rm|ra)"  player="PAPlayer" />
 | 
	
		
			
				|  |  | -+    <rule name="rtsp" protocols="rtsp" filetypes="!(rm|ra)"  player="audiodefaultplayer" />
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     <!-- Internet streams -->
 | 
	
		
			
				|  |  | -     <rule name="streams" internetstream="true">
 | 
	
		
			
				|  |  | --      <rule name="aacp/sdp" mimetypes="audio/aacp|application/sdp" player="DVDPlayer" />
 | 
	
		
			
				|  |  | --      <rule name="mp2" mimetypes="application/octet-stream" filetypes="mp2" player="PAPlayer" />
 | 
	
		
			
				|  |  | -+      <rule name="aacp/sdp" mimetypes="audio/aacp|application/sdp" player="videodefaultplayer" />
 | 
	
		
			
				|  |  | -+      <rule name="mp2" mimetypes="application/octet-stream" filetypes="mp2" player="audiodefaultplayer" />
 | 
	
		
			
				|  |  | -     </rule>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     <!-- DVDs -->
 | 
	
		
			
				|  |  | --    <rule name="dvd" dvd="true" player="DVDPlayer" />
 | 
	
		
			
				|  |  | --    <rule name="dvdimage" dvdimage="true" player="DVDPlayer" />
 | 
	
		
			
				|  |  | -+    <rule name="dvd" dvd="true" player="videodefaultdvdplayer" />
 | 
	
		
			
				|  |  | -+    <rule name="dvdfile" dvdfile="true" player="videodefaultdvdplayer" />
 | 
	
		
			
				|  |  | -+    <rule name="dvdimage" dvdimage="true" player="videodefaultdvdplayer" />
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     <!-- Only dvdplayer can handle these normally -->
 | 
	
		
			
				|  |  | --    <rule name="sdp/asf" filetypes="sdp|asf" player="DVDPlayer" />
 | 
	
		
			
				|  |  | -+    <rule name="sdp/asf" filetypes="sdp|asf" player="videodefaultplayer" />
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     <!-- Pass these to dvdplayer as we do not know if they are audio or video -->
 | 
	
		
			
				|  |  | --    <rule name="nsv" filetypes="nsv" player="DVDPlayer" />
 | 
	
		
			
				|  |  | -+    <rule name="nsv" filetypes="nsv" player="videodefaultplayer" />
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     <!-- pvr radio channels should be played by dvdplayer because they need buffering -->
 | 
	
		
			
				|  |  | --    <rule name="radio" filetypes="pvr" filename=".*/radio/.*" player="DVDPlayer" />
 | 
	
		
			
				|  |  | -+    <rule name="radio" filetypes="pvr" filename=".*/radio/.*" player="videodefaultplayer" />
 | 
	
		
			
				|  |  | -   </rules>
 | 
	
		
			
				|  |  | - </playercorefactory>
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 5c4de293325bba93c4b820aed6863ee8d732ce2c Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 11 Jan 2014 18:23:42 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 39/94] [rbp] Don't force dvdplayer for airplay
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/network/AirPlayServer.cpp | 2 ++
 | 
	
		
			
				|  |  | - 1 file changed, 2 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/network/AirPlayServer.cpp b/xbmc/network/AirPlayServer.cpp
 | 
	
		
			
				|  |  | -index 8040d9b..182daaa 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/network/AirPlayServer.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/network/AirPlayServer.cpp
 | 
	
		
			
				|  |  | -@@ -906,9 +906,11 @@ int CAirPlayServer::CTCPClient::ProcessRequest( CStdString& responseHeader,
 | 
	
		
			
				|  |  | -       CFileItem fileToPlay(location, false);
 | 
	
		
			
				|  |  | -       fileToPlay.SetProperty("StartPercent", position*100.0f);
 | 
	
		
			
				|  |  | -       ServerInstance->AnnounceToClients(EVENT_LOADING);
 | 
	
		
			
				|  |  | -+#ifndef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -       // froce to internal dvdplayer cause it is the only
 | 
	
		
			
				|  |  | -       // one who will work well with airplay
 | 
	
		
			
				|  |  | -       g_application.m_eForcedNextPlayer = EPC_DVDPLAYER;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -       CApplicationMessenger::Get().MediaPlay(fileToPlay);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 454b77543018aac5d7e70769ef13231ae16eefb9 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 13 Jan 2014 13:11:06 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 40/94] [rbp] Give plugins omxplayer when they request
 | 
	
		
			
				|  |  | - dvdplayer on pi
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/interfaces/legacy/ModuleXbmc.cpp | 4 ++++
 | 
	
		
			
				|  |  | - 1 file changed, 4 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/interfaces/legacy/ModuleXbmc.cpp b/xbmc/interfaces/legacy/ModuleXbmc.cpp
 | 
	
		
			
				|  |  | -index 16f0174..b172d47 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/interfaces/legacy/ModuleXbmc.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/interfaces/legacy/ModuleXbmc.cpp
 | 
	
		
			
				|  |  | -@@ -536,7 +536,11 @@ namespace XBMCAddon
 | 
	
		
			
				|  |  | -     int getPLAYLIST_MUSIC() { return PLAYLIST_MUSIC; }
 | 
	
		
			
				|  |  | -     int getPLAYLIST_VIDEO() { return PLAYLIST_VIDEO; }
 | 
	
		
			
				|  |  | -     int getPLAYER_CORE_AUTO() { return EPC_NONE; }
 | 
	
		
			
				|  |  | -+#ifdef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -+    int getPLAYER_CORE_DVDPLAYER() { return EPC_OMXPLAYER; }
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -     int getPLAYER_CORE_DVDPLAYER() { return EPC_DVDPLAYER; }
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -     int getPLAYER_CORE_MPLAYER() { return EPC_MPLAYER; }
 | 
	
		
			
				|  |  | -     int getPLAYER_CORE_PAPLAYER() { return EPC_PAPLAYER; }
 | 
	
		
			
				|  |  | -     int getTRAY_OPEN() { return TRAY_OPEN; }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7201ee3e0ca664518eaaf3142682b294c34c69c0 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Tue, 14 Jan 2014 18:04:07 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 41/94] [rbp] Allow ALSA to be chosen in addition to Pi sink
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Needs --enable-alsa in ./configure step and alsa support on platform
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - configure.in                             |  1 -
 | 
	
		
			
				|  |  | - tools/depends/target/Makefile            |  6 +++---
 | 
	
		
			
				|  |  | - xbmc/cores/AudioEngine/AESinkFactory.cpp | 17 +++++++++++++++--
 | 
	
		
			
				|  |  | - 3 files changed, 18 insertions(+), 6 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/configure.in b/configure.in
 | 
	
		
			
				|  |  | -index a195d00..34dd038 100644
 | 
	
		
			
				|  |  | ---- a/configure.in
 | 
	
		
			
				|  |  | -+++ b/configure.in
 | 
	
		
			
				|  |  | -@@ -742,7 +742,6 @@ case $use_platform in
 | 
	
		
			
				|  |  | -      use_arch="arm"
 | 
	
		
			
				|  |  | -      use_cpu=arm1176jzf-s
 | 
	
		
			
				|  |  | -      use_hardcoded_tables="yes"
 | 
	
		
			
				|  |  | --     use_alsa="no"
 | 
	
		
			
				|  |  | -      ARCH="arm"
 | 
	
		
			
				|  |  | -      AC_DEFINE(HAS_EGLGLES, [1], [Define if supporting EGL based GLES Framebuffer])
 | 
	
		
			
				|  |  | -      USE_OMXLIB=1; AC_DEFINE([HAVE_OMXLIB],[1],["Define to 1 if OMX libs is enabled"])
 | 
	
		
			
				|  |  | -diff --git a/tools/depends/target/Makefile b/tools/depends/target/Makefile
 | 
	
		
			
				|  |  | -index 4588917..0fbd3e7 100644
 | 
	
		
			
				|  |  | ---- a/tools/depends/target/Makefile
 | 
	
		
			
				|  |  | -+++ b/tools/depends/target/Makefile
 | 
	
		
			
				|  |  | -@@ -55,10 +55,10 @@ endif
 | 
	
		
			
				|  |  | - ALSA_LIB=
 | 
	
		
			
				|  |  | - LINUX_SYSTEM_LIBS=
 | 
	
		
			
				|  |  | - ifeq ($(OS),linux)
 | 
	
		
			
				|  |  | --  #not for raspberry pi
 | 
	
		
			
				|  |  | -+  DEPENDS += alsa-lib
 | 
	
		
			
				|  |  | -+  ALSA_LIB = alsa-lib
 | 
	
		
			
				|  |  | -   ifneq ($(CPU),arm)
 | 
	
		
			
				|  |  | --    DEPENDS += alsa-lib libsdl linux-system-libs
 | 
	
		
			
				|  |  | --    ALSA_LIB = alsa-lib
 | 
	
		
			
				|  |  | -+    DEPENDS += libsdl linux-system-libs
 | 
	
		
			
				|  |  | -     LINUX_SYSTEM_LIBS = linux-system-libs
 | 
	
		
			
				|  |  | -   endif
 | 
	
		
			
				|  |  | - endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/AESinkFactory.cpp b/xbmc/cores/AudioEngine/AESinkFactory.cpp
 | 
	
		
			
				|  |  | -index e493123..7df6807 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/AESinkFactory.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/AESinkFactory.cpp
 | 
	
		
			
				|  |  | -@@ -27,6 +27,7 @@
 | 
	
		
			
				|  |  | -   #include "Sinks/AESinkAUDIOTRACK.h"
 | 
	
		
			
				|  |  | - #elif defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | -   #include "Sinks/AESinkPi.h"
 | 
	
		
			
				|  |  | -+  #include "Sinks/AESinkALSA.h"
 | 
	
		
			
				|  |  | - #elif defined(TARGET_DARWIN_IOS)
 | 
	
		
			
				|  |  | -   #include "Sinks/AESinkDARWINIOS.h"
 | 
	
		
			
				|  |  | - #elif defined(TARGET_DARWIN_OSX)
 | 
	
		
			
				|  |  | -@@ -66,6 +67,7 @@ void CAESinkFactory::ParseDevice(std::string &device, std::string &driver)
 | 
	
		
			
				|  |  | -         driver == "AUDIOTRACK"  ||
 | 
	
		
			
				|  |  | - #elif defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | -         driver == "PI"          ||
 | 
	
		
			
				|  |  | -+        driver == "ALSA"        ||
 | 
	
		
			
				|  |  | - #elif defined(TARGET_DARWIN_IOS)
 | 
	
		
			
				|  |  | -         driver == "DARWINIOS"  ||
 | 
	
		
			
				|  |  | - #elif defined(TARGET_DARWIN_OSX)
 | 
	
		
			
				|  |  | -@@ -104,7 +106,12 @@ IAESink *CAESinkFactory::TrySink(std::string &driver, std::string &device, AEAud
 | 
	
		
			
				|  |  | - #elif defined(TARGET_ANDROID)
 | 
	
		
			
				|  |  | -   sink = new CAESinkAUDIOTRACK();
 | 
	
		
			
				|  |  | - #elif defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | --  sink = new CAESinkPi();
 | 
	
		
			
				|  |  | -+  else if (driver == "PI")
 | 
	
		
			
				|  |  | -+    sink = new CAESinkPi();
 | 
	
		
			
				|  |  | -+  #if defined(HAS_ALSA)
 | 
	
		
			
				|  |  | -+  else if (driver == "ALSA")
 | 
	
		
			
				|  |  | -+    sink = new CAESinkALSA();
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | - #elif defined(TARGET_DARWIN_IOS)
 | 
	
		
			
				|  |  | -   sink = new CAESinkDARWINIOS();
 | 
	
		
			
				|  |  | - #elif defined(TARGET_DARWIN_OSX)
 | 
	
		
			
				|  |  | -@@ -194,7 +201,13 @@ void CAESinkFactory::EnumerateEx(AESinkInfoList &list, bool force)
 | 
	
		
			
				|  |  | -   CAESinkPi::EnumerateDevicesEx(info.m_deviceInfoList, force);
 | 
	
		
			
				|  |  | -   if(!info.m_deviceInfoList.empty())
 | 
	
		
			
				|  |  | -     list.push_back(info);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+  #if defined(HAS_ALSA)
 | 
	
		
			
				|  |  | -+  info.m_deviceInfoList.clear();
 | 
	
		
			
				|  |  | -+  info.m_sinkName = "ALSA";
 | 
	
		
			
				|  |  | -+  CAESinkALSA::EnumerateDevicesEx(info.m_deviceInfoList, force);
 | 
	
		
			
				|  |  | -+  if(!info.m_deviceInfoList.empty())
 | 
	
		
			
				|  |  | -+    list.push_back(info);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | - #elif defined(TARGET_DARWIN_IOS)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   info.m_deviceInfoList.clear();
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 8ffa85ccdc4760751849d75d37924fbf6cb1b1c8 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 16 Jan 2014 01:39:29 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 42/94] [omxcodec] Add hardware decode to dvdplayer for Pi
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Hijack the abandoned OpenMaxVideo codec
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - configure.in                                       |   21 +-
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp    |   12 +-
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/LinuxRendererGLES.h      |    6 +-
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/RenderManager.cpp        |    2 +-
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp |    7 +-
 | 
	
		
			
				|  |  | - .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h      |    7 +-
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp       |  295 +---
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecOpenMax.h         |   34 +-
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in   |    1 -
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp   |  269 ----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h     |  116 --
 | 
	
		
			
				|  |  | - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp     | 1418 ++++++++++----------
 | 
	
		
			
				|  |  | - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h |  120 +-
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDPlayer.cpp                 |    2 +
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp            |   21 +-
 | 
	
		
			
				|  |  | - xbmc/linux/OMXCore.cpp                             |   45 +-
 | 
	
		
			
				|  |  | - xbmc/linux/OMXCore.h                               |    2 +-
 | 
	
		
			
				|  |  | - 17 files changed, 894 insertions(+), 1484 deletions(-)
 | 
	
		
			
				|  |  | - delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp
 | 
	
		
			
				|  |  | - delete mode 100644 xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/configure.in b/configure.in
 | 
	
		
			
				|  |  | -index 34dd038..e7550c0 100644
 | 
	
		
			
				|  |  | ---- a/configure.in
 | 
	
		
			
				|  |  | -+++ b/configure.in
 | 
	
		
			
				|  |  | -@@ -1956,9 +1956,24 @@ if test "$host_vendor" = "apple" ; then
 | 
	
		
			
				|  |  | -   USE_OPENMAX=0
 | 
	
		
			
				|  |  | -   AC_MSG_NOTICE($openmax_disabled)
 | 
	
		
			
				|  |  | - elif test "$target_platform" = "target_raspberry_pi"; then
 | 
	
		
			
				|  |  | --  use_openmax="no"
 | 
	
		
			
				|  |  | --  USE_OPENMAX=0
 | 
	
		
			
				|  |  | --  AC_MSG_NOTICE($openmax_disabled)
 | 
	
		
			
				|  |  | -+  if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then
 | 
	
		
			
				|  |  | -+    use_openmax="yes"
 | 
	
		
			
				|  |  | -+    USE_OPENMAX=1
 | 
	
		
			
				|  |  | -+    HAVE_LIBOPENMAX=1
 | 
	
		
			
				|  |  | -+    AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.])
 | 
	
		
			
				|  |  | -+    AC_DEFINE([OMX_SKIP64BIT], [1], [Define to 1 if you have the 'LIBOPENMAX' library.])
 | 
	
		
			
				|  |  | -+    AC_MSG_NOTICE($openmax_enabled)
 | 
	
		
			
				|  |  | -+  elif test "$use_gles" = "yes" && test "$use_openmax" = "yes"; then
 | 
	
		
			
				|  |  | -+    use_openmax="yes"
 | 
	
		
			
				|  |  | -+    USE_OPENMAX=1
 | 
	
		
			
				|  |  | -+    HAVE_LIBOPENMAX=1
 | 
	
		
			
				|  |  | -+    AC_DEFINE([HAVE_LIBOPENMAX], [1], [Define to 1 if you have the 'LIBOPENMAX' library.])
 | 
	
		
			
				|  |  | -+    AC_MSG_NOTICE($openmax_enabled)
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    AC_MSG_NOTICE($openmax_disabled)
 | 
	
		
			
				|  |  | -+    use_openmax=no
 | 
	
		
			
				|  |  | -+    USE_OPENMAX=0
 | 
	
		
			
				|  |  | -+  fi
 | 
	
		
			
				|  |  | - else
 | 
	
		
			
				|  |  | -   if test "$use_gles" = "yes" && test "$use_openmax" = "auto"; then
 | 
	
		
			
				|  |  | -     PKG_CHECK_MODULES([OPENMAX], [libomxil-bellagio],
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -index 30c0601..6d879e3 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -@@ -44,7 +44,7 @@
 | 
	
		
			
				|  |  | - #include "windowing/WindowingFactory.h"
 | 
	
		
			
				|  |  | - #include "guilib/Texture.h"
 | 
	
		
			
				|  |  | - #include "lib/DllSwScale.h"
 | 
	
		
			
				|  |  | --#include "../dvdplayer/DVDCodecs/Video/OpenMaxVideo.h"
 | 
	
		
			
				|  |  | -+#include "DVDCodecs/Video/OpenMaxVideo.h"
 | 
	
		
			
				|  |  | - #include "threads/SingleLock.h"
 | 
	
		
			
				|  |  | - #include "RenderCapture.h"
 | 
	
		
			
				|  |  | - #include "RenderFormats.h"
 | 
	
		
			
				|  |  | -@@ -1330,6 +1330,10 @@ void CLinuxRendererGLES::RenderOpenMax(int index, int field)
 | 
	
		
			
				|  |  | -   glActiveTexture(GL_TEXTURE0);
 | 
	
		
			
				|  |  | -   glBindTexture(m_textureTarget, textureId);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
 | 
	
		
			
				|  |  | -+  glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
 | 
	
		
			
				|  |  | -+  glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   GLubyte idx[4] = {0, 1, 3, 2};        //determines order of triangle strip
 | 
	
		
			
				|  |  | -@@ -2676,10 +2680,12 @@ unsigned int CLinuxRendererGLES::GetProcessorSize()
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #ifdef HAVE_LIBOPENMAX
 | 
	
		
			
				|  |  | --void CLinuxRendererGLES::AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index)
 | 
	
		
			
				|  |  | -+void CLinuxRendererGLES::AddProcessor(COpenMaxVideoBuffer *openMaxBuffer, int index)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   YUVBUFFER &buf = m_buffers[index];
 | 
	
		
			
				|  |  | --  buf.openMaxBuffer = picture->openMaxBuffer;
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer *pic = openMaxBuffer->Acquire();
 | 
	
		
			
				|  |  | -+  SAFE_RELEASE(buf.openMaxBuffer);
 | 
	
		
			
				|  |  | -+  buf.openMaxBuffer = pic;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - #ifdef HAVE_VIDEOTOOLBOXDECODER
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
 | 
	
		
			
				|  |  | -index 45e9c20..0ca56a2 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
 | 
	
		
			
				|  |  | -@@ -39,7 +39,7 @@ class CRenderCapture;
 | 
	
		
			
				|  |  | - class CBaseTexture;
 | 
	
		
			
				|  |  | - namespace Shaders { class BaseYUV2RGBShader; }
 | 
	
		
			
				|  |  | - namespace Shaders { class BaseVideoFilterShader; }
 | 
	
		
			
				|  |  | --class COpenMaxVideo;
 | 
	
		
			
				|  |  | -+class COpenMaxVideoBuffer;
 | 
	
		
			
				|  |  | - class CDVDVideoCodecStageFright;
 | 
	
		
			
				|  |  | - class CDVDMediaCodecInfo;
 | 
	
		
			
				|  |  | - typedef std::vector<int>     Features;
 | 
	
		
			
				|  |  | -@@ -161,7 +161,7 @@ class CLinuxRendererGLES : public CBaseRenderer
 | 
	
		
			
				|  |  | -   virtual std::vector<ERenderFormat> SupportedFormats() { return m_formats; }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #ifdef HAVE_LIBOPENMAX
 | 
	
		
			
				|  |  | --  virtual void         AddProcessor(COpenMax* openMax, DVDVideoPicture *picture, int index);
 | 
	
		
			
				|  |  | -+  virtual void         AddProcessor(COpenMaxVideoBuffer *openMaxVideoBuffer, int index);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - #ifdef HAVE_VIDEOTOOLBOXDECODER
 | 
	
		
			
				|  |  | -   virtual void         AddProcessor(struct __CVBuffer *cvBufferRef, int index);
 | 
	
		
			
				|  |  | -@@ -275,7 +275,7 @@ class CLinuxRendererGLES : public CBaseRenderer
 | 
	
		
			
				|  |  | -     unsigned  flipindex; /* used to decide if this has been uploaded */
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #ifdef HAVE_LIBOPENMAX
 | 
	
		
			
				|  |  | --    OpenMaxVideoBuffer *openMaxBuffer;
 | 
	
		
			
				|  |  | -+    COpenMaxVideoBuffer *openMaxBuffer;
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - #ifdef HAVE_VIDEOTOOLBOXDECODER
 | 
	
		
			
				|  |  | -     struct __CVBuffer *cvBufferRef;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
 | 
	
		
			
				|  |  | -index 6832721..3503988 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
 | 
	
		
			
				|  |  | -@@ -912,7 +912,7 @@ int CXBMCRenderManager::AddVideoPicture(DVDVideoPicture& pic)
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - #ifdef HAVE_LIBOPENMAX
 | 
	
		
			
				|  |  | -   else if(pic.format == RENDER_FMT_OMXEGL)
 | 
	
		
			
				|  |  | --    m_pRenderer->AddProcessor(pic.openMax, &pic, index);
 | 
	
		
			
				|  |  | -+    m_pRenderer->AddProcessor(pic.openMaxBuffer, index);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - #ifdef TARGET_DARWIN
 | 
	
		
			
				|  |  | -   else if(pic.format == RENDER_FMT_CVBREF)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
 | 
	
		
			
				|  |  | -index 14ad038..18b8e3a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
 | 
	
		
			
				|  |  | -@@ -270,9 +270,12 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(HAVE_LIBOPENMAX)
 | 
	
		
			
				|  |  | --  if (CSettings::Get().GetBool("videoplayer.useomx") && !hint.software )
 | 
	
		
			
				|  |  | -+  if (!hint.software && CSettings::Get().GetBool("videoplayer.useomx"))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --      if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_VC1)
 | 
	
		
			
				|  |  | -+    if (hint.codec == AV_CODEC_ID_H264 || hint.codec == AV_CODEC_ID_H263 || hint.codec == AV_CODEC_ID_MPEG4 ||
 | 
	
		
			
				|  |  | -+        hint.codec == AV_CODEC_ID_MPEG1VIDEO || hint.codec == AV_CODEC_ID_MPEG2VIDEO ||
 | 
	
		
			
				|  |  | -+        hint.codec == AV_CODEC_ID_VP6 || hint.codec == AV_CODEC_ID_VP6F || hint.codec == AV_CODEC_ID_VP6A || hint.codec == AV_CODEC_ID_VP8 ||
 | 
	
		
			
				|  |  | -+        hint.codec == AV_CODEC_ID_THEORA || hint.codec == AV_CODEC_ID_MJPEG || hint.codec == AV_CODEC_ID_MJPEGB || hint.codec == AV_CODEC_ID_VC1 || hint.codec == AV_CODEC_ID_WMV3)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       if ( (pCodec = OpenCodec(new CDVDVideoCodecOpenMax(), hint, options)) ) return pCodec;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
 | 
	
		
			
				|  |  | -index f6751f4..dc047d7 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
 | 
	
		
			
				|  |  | -@@ -44,9 +44,7 @@ struct DVDCodecAvailableType
 | 
	
		
			
				|  |  | - namespace DXVA { class CSurfaceContext; }
 | 
	
		
			
				|  |  | - namespace VAAPI { struct CHolder; }
 | 
	
		
			
				|  |  | - namespace VDPAU { class CVdpauRenderPicture; }
 | 
	
		
			
				|  |  | --class COpenMax;
 | 
	
		
			
				|  |  | --class COpenMaxVideo;
 | 
	
		
			
				|  |  | --struct OpenMaxVideoBuffer;
 | 
	
		
			
				|  |  | -+class COpenMaxVideoBuffer;
 | 
	
		
			
				|  |  | - class CDVDVideoCodecStageFright;
 | 
	
		
			
				|  |  | - class CDVDMediaCodecInfo;
 | 
	
		
			
				|  |  | - typedef void* EGLImageKHR;
 | 
	
		
			
				|  |  | -@@ -75,8 +73,7 @@ struct DVDVideoPicture
 | 
	
		
			
				|  |  | -     };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     struct {
 | 
	
		
			
				|  |  | --      COpenMax *openMax;
 | 
	
		
			
				|  |  | --      OpenMaxVideoBuffer *openMaxBuffer;
 | 
	
		
			
				|  |  | -+      COpenMaxVideoBuffer *openMaxBuffer;
 | 
	
		
			
				|  |  | -     };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     struct {
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -index b2e7816..7d33192 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -@@ -29,113 +29,43 @@
 | 
	
		
			
				|  |  | - #include "DVDStreamInfo.h"
 | 
	
		
			
				|  |  | - #include "DVDVideoCodecOpenMax.h"
 | 
	
		
			
				|  |  | - #include "OpenMaxVideo.h"
 | 
	
		
			
				|  |  | -+#include "settings/Settings.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --#define CLASSNAME "COpenMax"
 | 
	
		
			
				|  |  | -+#define CLASSNAME "CDVDVideoCodecOpenMax"
 | 
	
		
			
				|  |  | - ////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | - ////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax() : CDVDVideoCodec()
 | 
	
		
			
				|  |  | -+CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_omx_decoder = NULL;
 | 
	
		
			
				|  |  | --  m_pFormatName = "omx-xxxx";
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_convert_bitstream = false;
 | 
	
		
			
				|  |  | --  memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | -   Dispose();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  // we always qualify even if DVDFactoryCodec does this too.
 | 
	
		
			
				|  |  | --  if (CSettings::Get().GetBool("videoplayer.useomx") && !hints.software)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_convert_bitstream = false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    switch (hints.codec)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      case AV_CODEC_ID_H264:
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        m_pFormatName = "omx-h264";
 | 
	
		
			
				|  |  | --        if (hints.extrasize < 7 || hints.extradata == NULL)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          CLog::Log(LOGNOTICE,
 | 
	
		
			
				|  |  | --            "%s::%s - avcC data too small or missing", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --          return false;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --        // valid avcC data (bitstream) always starts with the value 1 (version)
 | 
	
		
			
				|  |  | --        if ( *(char*)hints.extradata == 1 )
 | 
	
		
			
				|  |  | --          m_convert_bitstream = bitstream_convert_init(hints.extradata, hints.extrasize);
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --      case AV_CODEC_ID_MPEG4:
 | 
	
		
			
				|  |  | --        m_pFormatName = "omx-mpeg4";
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --      case AV_CODEC_ID_MPEG2VIDEO:
 | 
	
		
			
				|  |  | --        m_pFormatName = "omx-mpeg2";
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --      case AV_CODEC_ID_VC1:
 | 
	
		
			
				|  |  | --        m_pFormatName = "omx-vc1";
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --      default:
 | 
	
		
			
				|  |  | --        return false;
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    m_omx_decoder = new COpenMaxVideo;
 | 
	
		
			
				|  |  | --    if (!m_omx_decoder->Open(hints))
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR,
 | 
	
		
			
				|  |  | --        "%s::%s - failed to open, codec(%d), profile(%d), level(%d)", 
 | 
	
		
			
				|  |  | --        CLASSNAME, __func__, hints.codec, hints.profile, hints.level);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    // allocate a YV12 DVDVideoPicture buffer.
 | 
	
		
			
				|  |  | --    // first make sure all properties are reset.
 | 
	
		
			
				|  |  | --    memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    m_videobuffer.dts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | --    m_videobuffer.pts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | --    //m_videobuffer.format = RENDER_FMT_YUV420P;
 | 
	
		
			
				|  |  | --    m_videobuffer.format = RENDER_FMT_OMXEGL;
 | 
	
		
			
				|  |  | --    m_videobuffer.color_range  = 0;
 | 
	
		
			
				|  |  | --    m_videobuffer.color_matrix = 4;
 | 
	
		
			
				|  |  | --    m_videobuffer.iFlags  = DVP_FLAG_ALLOCATED;
 | 
	
		
			
				|  |  | --    m_videobuffer.iWidth  = hints.width;
 | 
	
		
			
				|  |  | --    m_videobuffer.iHeight = hints.height;
 | 
	
		
			
				|  |  | --    m_videobuffer.iDisplayWidth  = hints.width;
 | 
	
		
			
				|  |  | --    m_videobuffer.iDisplayHeight = hints.height;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    return true;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+  m_omx_decoder = new COpenMaxVideo;
 | 
	
		
			
				|  |  | -+  return m_omx_decoder->Open(hints, options);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  return false;
 | 
	
		
			
				|  |  | -+const char* CDVDVideoCodecOpenMax::GetName(void)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return m_omx_decoder ? m_omx_decoder->GetName() : "omx-xxx";
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CDVDVideoCodecOpenMax::Dispose()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (m_omx_decoder)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    m_omx_decoder->Close();
 | 
	
		
			
				|  |  | -+    m_omx_decoder->Dispose();
 | 
	
		
			
				|  |  | -     delete m_omx_decoder;
 | 
	
		
			
				|  |  | -     m_omx_decoder = NULL;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  if (m_videobuffer.iFlags & DVP_FLAG_ALLOCATED)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_videobuffer.iFlags = 0;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  if (m_convert_bitstream)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if (m_sps_pps_context.sps_pps_data)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      free(m_sps_pps_context.sps_pps_data);
 | 
	
		
			
				|  |  | --      m_sps_pps_context.sps_pps_data = NULL;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CDVDVideoCodecOpenMax::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | -@@ -145,37 +75,12 @@ void CDVDVideoCodecOpenMax::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - int CDVDVideoCodecOpenMax::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if (pData)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    int rtn;
 | 
	
		
			
				|  |  | --    int demuxer_bytes = iSize;
 | 
	
		
			
				|  |  | --    uint8_t *demuxer_content = pData;
 | 
	
		
			
				|  |  | --    bool bitstream_convered  = false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (m_convert_bitstream)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      // convert demuxer packet from bitstream to bytestream (AnnexB)
 | 
	
		
			
				|  |  | --      int bytestream_size = 0;
 | 
	
		
			
				|  |  | --      uint8_t *bytestream_buff = NULL;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      bitstream_convert(demuxer_content, demuxer_bytes, &bytestream_buff, &bytestream_size);
 | 
	
		
			
				|  |  | --      if (bytestream_buff && (bytestream_size > 0))
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        bitstream_convered = true;
 | 
	
		
			
				|  |  | --        demuxer_bytes = bytestream_size;
 | 
	
		
			
				|  |  | --        demuxer_content = bytestream_buff;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    rtn = m_omx_decoder->Decode(demuxer_content, demuxer_bytes, dts, pts);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (bitstream_convered)
 | 
	
		
			
				|  |  | --      free(demuxer_content);
 | 
	
		
			
				|  |  | -+  return m_omx_decoder->Decode(pData, iSize, dts, pts);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    return rtn;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  
 | 
	
		
			
				|  |  | --  return VC_BUFFER;
 | 
	
		
			
				|  |  | -+unsigned CDVDVideoCodecOpenMax::GetAllowedReferences()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return m_omx_decoder->GetAllowedReferences();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CDVDVideoCodecOpenMax::Reset(void)
 | 
	
		
			
				|  |  | -@@ -185,172 +90,12 @@ void CDVDVideoCodecOpenMax::Reset(void)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool CDVDVideoCodecOpenMax::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  m_omx_decoder->GetPicture(&m_videobuffer);
 | 
	
		
			
				|  |  | --  *pDvdVideoPicture = m_videobuffer;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return VC_PICTURE | VC_BUFFER;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --bool CDVDVideoCodecOpenMax::bitstream_convert_init(void *in_extradata, int in_extrasize)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  // based on h264_mp4toannexb_bsf.c (ffmpeg)
 | 
	
		
			
				|  |  | --  // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
 | 
	
		
			
				|  |  | --  // and Licensed GPL 2.1 or greater
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_sps_pps_size = 0;
 | 
	
		
			
				|  |  | --  m_sps_pps_context.sps_pps_data = NULL;
 | 
	
		
			
				|  |  | --  
 | 
	
		
			
				|  |  | --  // nothing to filter
 | 
	
		
			
				|  |  | --  if (!in_extradata || in_extrasize < 6)
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  uint16_t unit_size;
 | 
	
		
			
				|  |  | --  uint32_t total_size = 0;
 | 
	
		
			
				|  |  | --  uint8_t *out = NULL, unit_nb, sps_done = 0;
 | 
	
		
			
				|  |  | --  const uint8_t *extradata = (uint8_t*)in_extradata + 4;
 | 
	
		
			
				|  |  | --  static const uint8_t nalu_header[4] = {0, 0, 0, 1};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // retrieve length coded size
 | 
	
		
			
				|  |  | --  m_sps_pps_context.length_size = (*extradata++ & 0x3) + 1;
 | 
	
		
			
				|  |  | --  if (m_sps_pps_context.length_size == 3)
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // retrieve sps and pps unit(s)
 | 
	
		
			
				|  |  | --  unit_nb = *extradata++ & 0x1f;  // number of sps unit(s)
 | 
	
		
			
				|  |  | --  if (!unit_nb)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    unit_nb = *extradata++;       // number of pps unit(s)
 | 
	
		
			
				|  |  | --    sps_done++;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  while (unit_nb--)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    unit_size = extradata[0] << 8 | extradata[1];
 | 
	
		
			
				|  |  | --    total_size += unit_size + 4;
 | 
	
		
			
				|  |  | --    if ( (extradata + 2 + unit_size) > ((uint8_t*)in_extradata + in_extrasize) )
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      free(out);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    uint8_t* new_out = (uint8_t*)realloc(out, total_size);
 | 
	
		
			
				|  |  | --    if (new_out)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      out = new_out;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "bitstream_convert_init failed - %s : could not realloc the buffer out",  __FUNCTION__);
 | 
	
		
			
				|  |  | --      free(out);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    memcpy(out + total_size - unit_size - 4, nalu_header, 4);
 | 
	
		
			
				|  |  | --    memcpy(out + total_size - unit_size, extradata + 2, unit_size);
 | 
	
		
			
				|  |  | --    extradata += 2 + unit_size;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (!unit_nb && !sps_done++)
 | 
	
		
			
				|  |  | --      unit_nb = *extradata++;     // number of pps unit(s)
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_sps_pps_context.sps_pps_data = out;
 | 
	
		
			
				|  |  | --  m_sps_pps_context.size = total_size;
 | 
	
		
			
				|  |  | --  m_sps_pps_context.first_idr = 1;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return true;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --bool CDVDVideoCodecOpenMax::bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  // based on h264_mp4toannexb_bsf.c (ffmpeg)
 | 
	
		
			
				|  |  | --  // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
 | 
	
		
			
				|  |  | --  // and Licensed GPL 2.1 or greater
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  uint8_t *buf = pData;
 | 
	
		
			
				|  |  | --  uint32_t buf_size = iSize;
 | 
	
		
			
				|  |  | --  uint8_t  unit_type;
 | 
	
		
			
				|  |  | --  int32_t  nal_size;
 | 
	
		
			
				|  |  | --  uint32_t cumul_size = 0;
 | 
	
		
			
				|  |  | --  const uint8_t *buf_end = buf + buf_size;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  do
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if (buf + m_sps_pps_context.length_size > buf_end)
 | 
	
		
			
				|  |  | --      goto fail;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (m_sps_pps_context.length_size == 1)
 | 
	
		
			
				|  |  | --      nal_size = buf[0];
 | 
	
		
			
				|  |  | --    else if (m_sps_pps_context.length_size == 2)
 | 
	
		
			
				|  |  | --      nal_size = buf[0] << 8 | buf[1];
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --      nal_size = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    buf += m_sps_pps_context.length_size;
 | 
	
		
			
				|  |  | --    unit_type = *buf & 0x1f;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (buf + nal_size > buf_end || nal_size < 0)
 | 
	
		
			
				|  |  | --      goto fail;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    // prepend only to the first type 5 NAL unit of an IDR picture
 | 
	
		
			
				|  |  | --    if (m_sps_pps_context.first_idr && unit_type == 5)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      bitstream_alloc_and_copy(poutbuf, poutbuf_size,
 | 
	
		
			
				|  |  | --        m_sps_pps_context.sps_pps_data, m_sps_pps_context.size, buf, nal_size);
 | 
	
		
			
				|  |  | --      m_sps_pps_context.first_idr = 0;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      bitstream_alloc_and_copy(poutbuf, poutbuf_size, NULL, 0, buf, nal_size);
 | 
	
		
			
				|  |  | --      if (!m_sps_pps_context.first_idr && unit_type == 1)
 | 
	
		
			
				|  |  | --          m_sps_pps_context.first_idr = 1;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    buf += nal_size;
 | 
	
		
			
				|  |  | --    cumul_size += nal_size + m_sps_pps_context.length_size;
 | 
	
		
			
				|  |  | --  } while (cumul_size < buf_size);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return true;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --fail:
 | 
	
		
			
				|  |  | --  free(*poutbuf);
 | 
	
		
			
				|  |  | --  *poutbuf = NULL;
 | 
	
		
			
				|  |  | --  *poutbuf_size = 0;
 | 
	
		
			
				|  |  | --  return false;
 | 
	
		
			
				|  |  | -+  return m_omx_decoder->GetPicture(pDvdVideoPicture);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CDVDVideoCodecOpenMax::bitstream_alloc_and_copy(
 | 
	
		
			
				|  |  | --  uint8_t **poutbuf,      int *poutbuf_size,
 | 
	
		
			
				|  |  | --  const uint8_t *sps_pps, uint32_t sps_pps_size,
 | 
	
		
			
				|  |  | --  const uint8_t *in,      uint32_t in_size)
 | 
	
		
			
				|  |  | -+bool CDVDVideoCodecOpenMax::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  // based on h264_mp4toannexb_bsf.c (ffmpeg)
 | 
	
		
			
				|  |  | --  // which is Copyright (c) 2007 Benoit Fouet <benoit.fouet@free.fr>
 | 
	
		
			
				|  |  | --  // and Licensed GPL 2.1 or greater
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  #define CHD_WB32(p, d) { \
 | 
	
		
			
				|  |  | --    ((uint8_t*)(p))[3] = (d); \
 | 
	
		
			
				|  |  | --    ((uint8_t*)(p))[2] = (d) >> 8; \
 | 
	
		
			
				|  |  | --    ((uint8_t*)(p))[1] = (d) >> 16; \
 | 
	
		
			
				|  |  | --    ((uint8_t*)(p))[0] = (d) >> 24; }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  uint32_t offset = *poutbuf_size;
 | 
	
		
			
				|  |  | --  uint8_t nal_header_size = offset ? 3 : 4;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  *poutbuf_size += sps_pps_size + in_size + nal_header_size;
 | 
	
		
			
				|  |  | --  *poutbuf = (uint8_t*)realloc(*poutbuf, *poutbuf_size);
 | 
	
		
			
				|  |  | --  if (sps_pps)
 | 
	
		
			
				|  |  | --    memcpy(*poutbuf + offset, sps_pps, sps_pps_size);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  memcpy(*poutbuf + sps_pps_size + nal_header_size + offset, in, in_size);
 | 
	
		
			
				|  |  | --  if (!offset)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CHD_WB32(*poutbuf + sps_pps_size, 1);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    (*poutbuf + offset + sps_pps_size)[0] = 0;
 | 
	
		
			
				|  |  | --    (*poutbuf + offset + sps_pps_size)[1] = 0;
 | 
	
		
			
				|  |  | --    (*poutbuf + offset + sps_pps_size)[2] = 1;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+  return m_omx_decoder->ClearPicture(pDvdVideoPicture);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -index fb80d02..67cc235 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -@@ -23,7 +23,7 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "DVDVideoCodec.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --class COpenVideoMax;
 | 
	
		
			
				|  |  | -+class COpenMaxVideo;
 | 
	
		
			
				|  |  | - class CDVDVideoCodecOpenMax : public CDVDVideoCodec
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -@@ -36,39 +36,13 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec
 | 
	
		
			
				|  |  | -   virtual int  Decode(uint8_t *pData, int iSize, double dts, double pts);
 | 
	
		
			
				|  |  | -   virtual void Reset(void);
 | 
	
		
			
				|  |  | -   virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
 | 
	
		
			
				|  |  | -+  virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture);
 | 
	
		
			
				|  |  | -+  virtual unsigned GetAllowedReferences();
 | 
	
		
			
				|  |  | -   virtual void SetDropState(bool bDrop);
 | 
	
		
			
				|  |  | --  virtual const char* GetName(void) { return (const char*)m_pFormatName; }
 | 
	
		
			
				|  |  | -+  virtual const char* GetName(void);
 | 
	
		
			
				|  |  | -   
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | --  const char        *m_pFormatName;
 | 
	
		
			
				|  |  | -   COpenMaxVideo     *m_omx_decoder;
 | 
	
		
			
				|  |  | --  DVDVideoPicture   m_videobuffer;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // bitstream to bytestream (Annex B) conversion support.
 | 
	
		
			
				|  |  | --  bool bitstream_convert_init(void *in_extradata, int in_extrasize);
 | 
	
		
			
				|  |  | --  bool bitstream_convert(uint8_t* pData, int iSize, uint8_t **poutbuf, int *poutbuf_size);
 | 
	
		
			
				|  |  | --  static void bitstream_alloc_and_copy( uint8_t **poutbuf, int *poutbuf_size,
 | 
	
		
			
				|  |  | --    const uint8_t *sps_pps, uint32_t sps_pps_size, const uint8_t *in, uint32_t in_size);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  typedef struct omx_bitstream_ctx {
 | 
	
		
			
				|  |  | --      uint8_t  length_size;
 | 
	
		
			
				|  |  | --      uint8_t  first_idr;
 | 
	
		
			
				|  |  | --      uint8_t *sps_pps_data;
 | 
	
		
			
				|  |  | --      uint32_t size;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      omx_bitstream_ctx()
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        length_size = 0;
 | 
	
		
			
				|  |  | --        first_idr = 0;
 | 
	
		
			
				|  |  | --        sps_pps_data = NULL;
 | 
	
		
			
				|  |  | --        size = 0;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  } omx_bitstream_ctx;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  uint32_t          m_sps_pps_size;
 | 
	
		
			
				|  |  | --  omx_bitstream_ctx m_sps_pps_context;
 | 
	
		
			
				|  |  | --  bool              m_convert_bitstream;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
 | 
	
		
			
				|  |  | -index 8a97889..ebf7123 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/Makefile.in
 | 
	
		
			
				|  |  | -@@ -20,7 +20,6 @@ SRCS += DVDVideoCodecVDA.cpp
 | 
	
		
			
				|  |  | - SRCS += VDA.cpp
 | 
	
		
			
				|  |  | - endif
 | 
	
		
			
				|  |  | - ifeq (@USE_OPENMAX@,1)
 | 
	
		
			
				|  |  | --SRCS += OpenMax.cpp
 | 
	
		
			
				|  |  | - SRCS += OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | - SRCS += DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | - endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp
 | 
	
		
			
				|  |  | -deleted file mode 100644
 | 
	
		
			
				|  |  | -index 7b0a0c2ef..0000000
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.cpp
 | 
	
		
			
				|  |  | -+++ /dev/null
 | 
	
		
			
				|  |  | -@@ -1,269 +0,0 @@
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | -- *      Copyright (C) 2010-2013 Team XBMC
 | 
	
		
			
				|  |  | -- *      http://xbmc.org
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -- *  any later version.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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 XBMC; see the file COPYING.  If not, see
 | 
	
		
			
				|  |  | -- *  <http://www.gnu.org/licenses/>.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#if (defined HAVE_CONFIG_H) && (!defined TARGET_WINDOWS)
 | 
	
		
			
				|  |  | --  #include "config.h"
 | 
	
		
			
				|  |  | --#elif defined(TARGET_WINDOWS)
 | 
	
		
			
				|  |  | --#include "system.h"
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#if defined(HAVE_LIBOPENMAX)
 | 
	
		
			
				|  |  | --#include "OpenMax.h"
 | 
	
		
			
				|  |  | --#include "DynamicDll.h"
 | 
	
		
			
				|  |  | --#include "DVDClock.h"
 | 
	
		
			
				|  |  | --#include "DVDStreamInfo.h"
 | 
	
		
			
				|  |  | --#include "windowing/WindowingFactory.h"
 | 
	
		
			
				|  |  | --#include "DVDVideoCodec.h"
 | 
	
		
			
				|  |  | --#include "utils/log.h"
 | 
	
		
			
				|  |  | --#include "utils/TimeUtils.h"
 | 
	
		
			
				|  |  | --#include "ApplicationMessenger.h"
 | 
	
		
			
				|  |  | --#include "Application.h"
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#include <OMX_Core.h>
 | 
	
		
			
				|  |  | --#include <OMX_Component.h>
 | 
	
		
			
				|  |  | --#include <OMX_Index.h>
 | 
	
		
			
				|  |  | --#include <OMX_Image.h>
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#define CLASSNAME "COpenMax"
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --class DllLibOpenMaxInterface
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --public:
 | 
	
		
			
				|  |  | --  virtual ~DllLibOpenMaxInterface() {}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE OMX_Init(void) = 0;
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE OMX_Deinit(void) = 0;
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE OMX_GetHandle(
 | 
	
		
			
				|  |  | --    OMX_HANDLETYPE *pHandle, OMX_STRING cComponentName, OMX_PTR pAppData, OMX_CALLBACKTYPE *pCallBacks) = 0;
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE OMX_FreeHandle(OMX_HANDLETYPE hComponent) = 0;
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE OMX_GetComponentsOfRole(OMX_STRING role, OMX_U32 *pNumComps, OMX_U8 **compNames) = 0;
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE OMX_GetRolesOfComponent(OMX_STRING compName, OMX_U32 *pNumRoles, OMX_U8 **roles) = 0;
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE OMX_ComponentNameEnum(OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex) = 0;
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --class DllLibOpenMax : public DllDynamic, DllLibOpenMaxInterface
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  DECLARE_DLL_WRAPPER(DllLibOpenMax, "/usr/lib/libnvomx.so")
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Init)
 | 
	
		
			
				|  |  | --  DEFINE_METHOD0(OMX_ERRORTYPE, OMX_Deinit)
 | 
	
		
			
				|  |  | --  DEFINE_METHOD4(OMX_ERRORTYPE, OMX_GetHandle, (OMX_HANDLETYPE *p1, OMX_STRING p2, OMX_PTR p3, OMX_CALLBACKTYPE *p4))
 | 
	
		
			
				|  |  | --  DEFINE_METHOD1(OMX_ERRORTYPE, OMX_FreeHandle, (OMX_HANDLETYPE p1))
 | 
	
		
			
				|  |  | --  DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetComponentsOfRole, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
 | 
	
		
			
				|  |  | --  DEFINE_METHOD3(OMX_ERRORTYPE, OMX_GetRolesOfComponent, (OMX_STRING p1, OMX_U32 *p2, OMX_U8 **p3))
 | 
	
		
			
				|  |  | --  DEFINE_METHOD3(OMX_ERRORTYPE, OMX_ComponentNameEnum, (OMX_STRING p1, OMX_U32 p2, OMX_U32 p3))
 | 
	
		
			
				|  |  | --  BEGIN_METHOD_RESOLVE()
 | 
	
		
			
				|  |  | --    RESOLVE_METHOD(OMX_Init)
 | 
	
		
			
				|  |  | --    RESOLVE_METHOD(OMX_Deinit)
 | 
	
		
			
				|  |  | --    RESOLVE_METHOD(OMX_GetHandle)
 | 
	
		
			
				|  |  | --    RESOLVE_METHOD(OMX_FreeHandle)
 | 
	
		
			
				|  |  | --    RESOLVE_METHOD(OMX_GetComponentsOfRole)
 | 
	
		
			
				|  |  | --    RESOLVE_METHOD(OMX_GetRolesOfComponent)
 | 
	
		
			
				|  |  | --    RESOLVE_METHOD(OMX_ComponentNameEnum)
 | 
	
		
			
				|  |  | --  END_METHOD_RESOLVE()
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --#define OMX_INIT_STRUCTURE(a) \
 | 
	
		
			
				|  |  | --  memset(&(a), 0, sizeof(a)); \
 | 
	
		
			
				|  |  | --  (a).nSize = sizeof(a); \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nStep = OMX_VERSION_STEP
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --COpenMax::COpenMax()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --  m_dll = new DllLibOpenMax;
 | 
	
		
			
				|  |  | --  m_dll->Load();
 | 
	
		
			
				|  |  | --  m_is_open = false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_omx_decoder = NULL;
 | 
	
		
			
				|  |  | --  m_omx_client_state = DEAD;
 | 
	
		
			
				|  |  | --  m_omx_decoder_state = 0;
 | 
	
		
			
				|  |  | --  sem_init(m_omx_decoder_state_change, 0, 0);
 | 
	
		
			
				|  |  | --  /*
 | 
	
		
			
				|  |  | --  m_omx_flush_input  = (sem_t*)malloc(sizeof(sem_t));
 | 
	
		
			
				|  |  | --  sem_init(m_omx_flush_input, 0, 0);
 | 
	
		
			
				|  |  | --  m_omx_flush_output = (sem_t*)malloc(sizeof(sem_t));
 | 
	
		
			
				|  |  | --  sem_init(m_omx_flush_output, 0, 0);
 | 
	
		
			
				|  |  | --  */
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --COpenMax::~COpenMax()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --  /*
 | 
	
		
			
				|  |  | --  sem_destroy(m_omx_flush_input);
 | 
	
		
			
				|  |  | --  free(m_omx_flush_input);
 | 
	
		
			
				|  |  | --  sem_destroy(m_omx_flush_output);
 | 
	
		
			
				|  |  | --  free(m_omx_flush_output);
 | 
	
		
			
				|  |  | --  */
 | 
	
		
			
				|  |  | --  delete m_dll;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --// DecoderEventHandler -- OMX event callback
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::DecoderEventHandlerCallback(
 | 
	
		
			
				|  |  | --  OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | --  OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --  OMX_EVENTTYPE eEvent,
 | 
	
		
			
				|  |  | --  OMX_U32 nData1,
 | 
	
		
			
				|  |  | --  OMX_U32 nData2,
 | 
	
		
			
				|  |  | --  OMX_PTR pEventData)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  COpenMax *ctx = (COpenMax*)pAppData;
 | 
	
		
			
				|  |  | --  return ctx->DecoderEventHandler(hComponent, pAppData, eEvent, nData1, nData2, pEventData);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// DecoderEmptyBufferDone -- OpenMax input buffer has been emptied
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::DecoderEmptyBufferDoneCallback(
 | 
	
		
			
				|  |  | --  OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | --  OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --  OMX_BUFFERHEADERTYPE* pBuffer)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  COpenMax *ctx = (COpenMax*)pAppData;
 | 
	
		
			
				|  |  | --  return ctx->DecoderEmptyBufferDone( hComponent, pAppData, pBuffer);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// DecoderFillBufferDone -- OpenMax output buffer has been filled
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::DecoderFillBufferDoneCallback(
 | 
	
		
			
				|  |  | --  OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | --  OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --  OMX_BUFFERHEADERTYPE* pBuffer)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  COpenMax *ctx = (COpenMax*)pAppData;
 | 
	
		
			
				|  |  | --  return ctx->DecoderFillBufferDone(hComponent, pAppData, pBuffer);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// Wait for a component to transition to the specified state
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::WaitForState(OMX_STATETYPE state)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  OMX_STATETYPE test_state;
 | 
	
		
			
				|  |  | --  int tries = 0;
 | 
	
		
			
				|  |  | --  struct timespec timeout;
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_error = OMX_GetState(m_omx_decoder, &test_state);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - waiting for state(%d)\n", CLASSNAME, __func__, state);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --  while ((omx_error == OMX_ErrorNone) && (test_state != state)) 
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    clock_gettime(CLOCK_REALTIME, &timeout);
 | 
	
		
			
				|  |  | --    timeout.tv_sec += 1;
 | 
	
		
			
				|  |  | --    sem_timedwait(m_omx_decoder_state_change, &timeout);
 | 
	
		
			
				|  |  | --    if (errno == ETIMEDOUT)
 | 
	
		
			
				|  |  | --      tries++;
 | 
	
		
			
				|  |  | --    if (tries > 5)
 | 
	
		
			
				|  |  | --      return OMX_ErrorUndefined;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_error = OMX_GetState(m_omx_decoder, &test_state);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return omx_error;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// SetStateForAllComponents
 | 
	
		
			
				|  |  | --// Blocks until all state changes have completed
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::SetStateForComponent(OMX_STATETYPE state)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - state(%d)\n", CLASSNAME, __func__, state);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --  omx_err = OMX_SendCommand(m_omx_decoder, OMX_CommandStateSet, state, 0);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s - OMX_CommandStateSet failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    omx_err = WaitForState(state);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return omx_err;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --bool COpenMax::Initialize( const CStdString &decoder_name)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err = m_dll->OMX_Init();
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR,
 | 
	
		
			
				|  |  | --      "%s::%s - OpenMax failed to init, status(%d), ", // codec(%d), profile(%d), level(%d)
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, omx_err );//, hints.codec, hints.profile, hints.level);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // Get video decoder handle setting up callbacks, component is in loaded state on return.
 | 
	
		
			
				|  |  | --  static OMX_CALLBACKTYPE decoder_callbacks = {
 | 
	
		
			
				|  |  | --    &DecoderEventHandlerCallback, &DecoderEmptyBufferDoneCallback, &DecoderFillBufferDoneCallback };
 | 
	
		
			
				|  |  | --  omx_err = m_dll->OMX_GetHandle(&m_omx_decoder, (char*)decoder_name.c_str(), this, &decoder_callbacks);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR,
 | 
	
		
			
				|  |  | --      "%s::%s - could not get decoder handle\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --    m_dll->OMX_Deinit();
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return true;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void COpenMax::Deinitialize()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  CLog::Log(LOGERROR,
 | 
	
		
			
				|  |  | --    "%s::%s - failed to get component port parameter\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --  m_dll->OMX_FreeHandle(m_omx_decoder);
 | 
	
		
			
				|  |  | --  m_omx_decoder = NULL;
 | 
	
		
			
				|  |  | --  m_dll->OMX_Deinit();
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// OpenMax decoder callback routines.
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --  OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return OMX_ErrorNone;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::DecoderEmptyBufferDone(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return OMX_ErrorNone;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMax::DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return OMX_ErrorNone;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h
 | 
	
		
			
				|  |  | -deleted file mode 100644
 | 
	
		
			
				|  |  | -index 0d9ff18..0000000
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMax.h
 | 
	
		
			
				|  |  | -+++ /dev/null
 | 
	
		
			
				|  |  | -@@ -1,116 +0,0 @@
 | 
	
		
			
				|  |  | --#pragma once
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | -- *      Copyright (C) 2010-2013 Team XBMC
 | 
	
		
			
				|  |  | -- *      http://xbmc.org
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -- *  any later version.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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 XBMC; see the file COPYING.  If not, see
 | 
	
		
			
				|  |  | -- *  <http://www.gnu.org/licenses/>.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#if defined(HAVE_LIBOPENMAX)
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#include "cores/dvdplayer/DVDStreamInfo.h"
 | 
	
		
			
				|  |  | --#include "DVDVideoCodec.h"
 | 
	
		
			
				|  |  | --#include "threads/Event.h"
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#include <queue>
 | 
	
		
			
				|  |  | --#include <semaphore.h>
 | 
	
		
			
				|  |  | --#include <OMX_Core.h>
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --// debug spew defines
 | 
	
		
			
				|  |  | --#if 0
 | 
	
		
			
				|  |  | --#define OMX_DEBUG_VERBOSE
 | 
	
		
			
				|  |  | --#define OMX_DEBUG_EVENTHANDLER
 | 
	
		
			
				|  |  | --#define OMX_DEBUG_FILLBUFFERDONE
 | 
	
		
			
				|  |  | --#define OMX_DEBUG_EMPTYBUFFERDONE
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --typedef struct omx_codec_capability {
 | 
	
		
			
				|  |  | --    // level is OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, 
 | 
	
		
			
				|  |  | --    // or OMX_VIDEO_MPEG4PROFILETYPE depending on context.
 | 
	
		
			
				|  |  | --    OMX_U32 level;
 | 
	
		
			
				|  |  | --    // level is OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE, 
 | 
	
		
			
				|  |  | --    // or OMX_VIDEO_MPEG4PROFILETYPE depending on context.
 | 
	
		
			
				|  |  | --    OMX_U32 profile;
 | 
	
		
			
				|  |  | --} omx_codec_capability;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --typedef struct omx_demux_packet {
 | 
	
		
			
				|  |  | --  OMX_U8 *buff;
 | 
	
		
			
				|  |  | --  int size;
 | 
	
		
			
				|  |  | --  double dts;
 | 
	
		
			
				|  |  | --  double pts;
 | 
	
		
			
				|  |  | --} omx_demux_packet;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --class DllLibOpenMax;
 | 
	
		
			
				|  |  | --class COpenMax
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --public:
 | 
	
		
			
				|  |  | --  COpenMax();
 | 
	
		
			
				|  |  | --  virtual ~COpenMax();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --protected:
 | 
	
		
			
				|  |  | --  enum OMX_CLIENT_STATE {
 | 
	
		
			
				|  |  | --      DEAD,
 | 
	
		
			
				|  |  | --      LOADED,
 | 
	
		
			
				|  |  | --      LOADED_TO_IDLE,
 | 
	
		
			
				|  |  | --      IDLE_TO_EXECUTING,
 | 
	
		
			
				|  |  | --      EXECUTING,
 | 
	
		
			
				|  |  | --      EXECUTING_TO_IDLE,
 | 
	
		
			
				|  |  | --      IDLE_TO_LOADED,
 | 
	
		
			
				|  |  | --      RECONFIGURING,
 | 
	
		
			
				|  |  | --      ERROR
 | 
	
		
			
				|  |  | --  };
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // initialize OpenMax and get decoder component
 | 
	
		
			
				|  |  | --  bool Initialize( const CStdString &decoder_name);
 | 
	
		
			
				|  |  | --  void Deinitialize();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // OpenMax Decoder delegate callback routines.
 | 
	
		
			
				|  |  | --  static OMX_ERRORTYPE DecoderEventHandlerCallback(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --    OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
 | 
	
		
			
				|  |  | --  static OMX_ERRORTYPE DecoderEmptyBufferDoneCallback(
 | 
	
		
			
				|  |  | --    OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
 | 
	
		
			
				|  |  | --  static OMX_ERRORTYPE DecoderFillBufferDoneCallback(
 | 
	
		
			
				|  |  | --    OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // OpenMax decoder callback routines.
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --    OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE DecoderEmptyBufferDone(
 | 
	
		
			
				|  |  | --    OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE DecoderFillBufferDone(
 | 
	
		
			
				|  |  | --    OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // OpenMax helper routines
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE WaitForState(OMX_STATETYPE state);
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE SetStateForComponent(OMX_STATETYPE state);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  DllLibOpenMax     *m_dll;
 | 
	
		
			
				|  |  | --  bool              m_is_open;
 | 
	
		
			
				|  |  | --  OMX_HANDLETYPE    m_omx_decoder;   // openmax decoder component reference
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // OpenMax state tracking
 | 
	
		
			
				|  |  | --  OMX_CLIENT_STATE  m_omx_client_state;
 | 
	
		
			
				|  |  | --  volatile int      m_omx_decoder_state;
 | 
	
		
			
				|  |  | --  sem_t             *m_omx_decoder_state_change;
 | 
	
		
			
				|  |  | --  std::vector<omx_codec_capability> m_omx_decoder_capabilities;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --private:
 | 
	
		
			
				|  |  | --  COpenMax(const COpenMax& other);
 | 
	
		
			
				|  |  | --  COpenMax& operator=(const COpenMax&);
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index dcbdb1e..aca2e0d 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -32,673 +32,891 @@
 | 
	
		
			
				|  |  | - #include "DVDVideoCodec.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - #include "utils/TimeUtils.h"
 | 
	
		
			
				|  |  | -+#include "settings/Settings.h"
 | 
	
		
			
				|  |  | - #include "ApplicationMessenger.h"
 | 
	
		
			
				|  |  | - #include "Application.h"
 | 
	
		
			
				|  |  | -+#include "threads/Atomics.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --#include <OMX_Core.h>
 | 
	
		
			
				|  |  | --#include <OMX_Component.h>
 | 
	
		
			
				|  |  | --#include <OMX_Index.h>
 | 
	
		
			
				|  |  | --#include <OMX_Image.h>
 | 
	
		
			
				|  |  | -+#include <IL/OMX_Core.h>
 | 
	
		
			
				|  |  | -+#include <IL/OMX_Component.h>
 | 
	
		
			
				|  |  | -+#include <IL/OMX_Index.h>
 | 
	
		
			
				|  |  | -+#include <IL/OMX_Image.h>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#include "cores/omxplayer/OMXImage.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define DTS_QUEUE
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define DEFAULT_TIMEOUT 1000
 | 
	
		
			
				|  |  | -+#ifdef _DEBUG
 | 
	
		
			
				|  |  | -+#define OMX_DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define CLASSNAME "COpenMaxVideo"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --// TODO: These are Nvidia Tegra2 dependent, need to dynamiclly find the
 | 
	
		
			
				|  |  | --// right codec matched to video format.
 | 
	
		
			
				|  |  | --#define OMX_H264BASE_DECODER    "OMX.Nvidia.h264.decode"
 | 
	
		
			
				|  |  | --// OMX.Nvidia.h264ext.decode segfaults, not sure why.
 | 
	
		
			
				|  |  | --//#define OMX_H264MAIN_DECODER  "OMX.Nvidia.h264ext.decode"
 | 
	
		
			
				|  |  | --#define OMX_H264MAIN_DECODER    "OMX.Nvidia.h264.decode"
 | 
	
		
			
				|  |  | --#define OMX_H264HIGH_DECODER    "OMX.Nvidia.h264ext.decode"
 | 
	
		
			
				|  |  | --#define OMX_MPEG4_DECODER       "OMX.Nvidia.mp4.decode"
 | 
	
		
			
				|  |  | --#define OMX_MPEG4EXT_DECODER    "OMX.Nvidia.mp4ext.decode"
 | 
	
		
			
				|  |  | --#define OMX_MPEG2V_DECODER      "OMX.Nvidia.mpeg2v.decode"
 | 
	
		
			
				|  |  | --#define OMX_VC1_DECODER         "OMX.Nvidia.vc1.decode"
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// EGL extension functions
 | 
	
		
			
				|  |  | --static PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR;
 | 
	
		
			
				|  |  | --static PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR;
 | 
	
		
			
				|  |  | --#define GETEXTENSION(type, ext) \
 | 
	
		
			
				|  |  | --do \
 | 
	
		
			
				|  |  | --{ \
 | 
	
		
			
				|  |  | --    ext = (type) eglGetProcAddress(#ext); \
 | 
	
		
			
				|  |  | --    if (!ext) \
 | 
	
		
			
				|  |  | --    { \
 | 
	
		
			
				|  |  | --        CLog::Log(LOGERROR, "%s::%s - ERROR getting proc addr of " #ext "\n", CLASSNAME, __func__); \
 | 
	
		
			
				|  |  | --    } \
 | 
	
		
			
				|  |  | --} while (0);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#define OMX_INIT_STRUCTURE(a) \
 | 
	
		
			
				|  |  | --  memset(&(a), 0, sizeof(a)); \
 | 
	
		
			
				|  |  | --  (a).nSize = sizeof(a); \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nVersionMajor = OMX_VERSION_MAJOR; \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nVersionMinor = OMX_VERSION_MINOR; \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nRevision = OMX_VERSION_REVISION; \
 | 
	
		
			
				|  |  | --  (a).nVersion.s.nStep = OMX_VERSION_STEP
 | 
	
		
			
				|  |  | -+COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
 | 
	
		
			
				|  |  | -+    : m_omv(omv), m_refs(0)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | -+  omx_buffer = NULL;
 | 
	
		
			
				|  |  | -+  width = 0;
 | 
	
		
			
				|  |  | -+  height = 0;
 | 
	
		
			
				|  |  | -+  index = 0;
 | 
	
		
			
				|  |  | -+  egl_image = 0;
 | 
	
		
			
				|  |  | -+  texture_id = 0;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+COpenMaxVideoBuffer::~COpenMaxVideoBuffer()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --COpenMaxVideo::COpenMaxVideo()
 | 
	
		
			
				|  |  | -+// DecoderFillBufferDone -- OpenMax output buffer has been filled
 | 
	
		
			
				|  |  | -+static OMX_ERRORTYPE DecoderFillBufferDoneCallback(
 | 
	
		
			
				|  |  | -+  OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | -+  OMX_PTR pAppData,
 | 
	
		
			
				|  |  | -+  OMX_BUFFERHEADERTYPE* pBuffer)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer *pic = static_cast<COpenMaxVideoBuffer*>(pBuffer->pAppPrivate);
 | 
	
		
			
				|  |  | -+  COpenMaxVideo *ctx = pic->m_omv;
 | 
	
		
			
				|  |  | -+  return ctx->DecoderFillBufferDone(hComponent, pBuffer);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+COpenMaxVideoBuffer* COpenMaxVideoBuffer::Acquire()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  long count = AtomicIncrement(&m_refs);
 | 
	
		
			
				|  |  | -+  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, count);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  (void)count;
 | 
	
		
			
				|  |  | -+  return this;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+long COpenMaxVideoBuffer::Release()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  m_portChanging = false;
 | 
	
		
			
				|  |  | -+  long count = AtomicDecrement(&m_refs);
 | 
	
		
			
				|  |  | -+  if (count == 0)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_omv->ReleaseOpenMaxBuffer(this);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, count);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return count;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  pthread_mutex_init(&m_omx_input_mutex, NULL);
 | 
	
		
			
				|  |  | -+void COpenMaxVideoBuffer::Sync()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p ref:%ld", CLASSNAME, __func__, this, m_refs);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  Release();
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+COpenMaxVideo::COpenMaxVideo()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | -   pthread_mutex_init(&m_omx_output_mutex, NULL);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_omx_decoder_state_change = (sem_t*)malloc(sizeof(sem_t));
 | 
	
		
			
				|  |  | --  sem_init(m_omx_decoder_state_change, 0, 0);
 | 
	
		
			
				|  |  | --  memset(&m_videobuffer, 0, sizeof(DVDVideoPicture));
 | 
	
		
			
				|  |  | -   m_drop_state = false;
 | 
	
		
			
				|  |  | -   m_decoded_width = 0;
 | 
	
		
			
				|  |  | -   m_decoded_height = 0;
 | 
	
		
			
				|  |  | --  m_omx_input_eos = false;
 | 
	
		
			
				|  |  | --  m_omx_input_port = 0;
 | 
	
		
			
				|  |  | --  m_omx_output_eos = false;
 | 
	
		
			
				|  |  | --  m_omx_output_port = 0;
 | 
	
		
			
				|  |  | --  m_videoplayback_done = false;
 | 
	
		
			
				|  |  | -+  m_egl_buffer_count = 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_port_settings_changed = false;
 | 
	
		
			
				|  |  | -+  m_pFormatName = "omx-xxxx";
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | --  if (m_is_open)
 | 
	
		
			
				|  |  | --    Close();
 | 
	
		
			
				|  |  | --  pthread_mutex_destroy(&m_omx_input_mutex);
 | 
	
		
			
				|  |  | -+  if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (m_omx_tunnel.IsInitialized())
 | 
	
		
			
				|  |  | -+      m_omx_tunnel.Deestablish();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    StopDecoder();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (m_omx_egl_render.IsInitialized())
 | 
	
		
			
				|  |  | -+      m_omx_egl_render.Deinitialize();
 | 
	
		
			
				|  |  | -+    if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -+      m_omx_decoder.Deinitialize();
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   pthread_mutex_destroy(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | --  sem_destroy(m_omx_decoder_state_change);
 | 
	
		
			
				|  |  | --  free(m_omx_decoder_state_change);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --bool COpenMaxVideo::Open(CDVDStreamInfo &hints)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  // we always qualify even if DVDFactoryCodec does this too.
 | 
	
		
			
				|  |  | -+  if (!CSettings::Get().GetBool("videoplayer.useomx") || hints.software)
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --  std::string decoder_name;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_decoded_width  = hints.width;
 | 
	
		
			
				|  |  | -   m_decoded_height = hints.height;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_egl_display = g_Windowing.GetEGLDisplay();
 | 
	
		
			
				|  |  | -+  m_egl_context = g_Windowing.GetEGLContext();
 | 
	
		
			
				|  |  | -+  m_egl_buffer_count = 4;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_codingType = OMX_VIDEO_CodingUnused;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   switch (hints.codec)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     case AV_CODEC_ID_H264:
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      switch(hints.profile)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        case FF_PROFILE_H264_BASELINE:
 | 
	
		
			
				|  |  | --          // (role name) video_decoder.avc
 | 
	
		
			
				|  |  | --          // H.264 Baseline profile
 | 
	
		
			
				|  |  | --          decoder_name = OMX_H264BASE_DECODER;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case FF_PROFILE_H264_MAIN:
 | 
	
		
			
				|  |  | --          // (role name) video_decoder.avc
 | 
	
		
			
				|  |  | --          // H.264 Main profile
 | 
	
		
			
				|  |  | --          decoder_name = OMX_H264MAIN_DECODER;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case FF_PROFILE_H264_HIGH:
 | 
	
		
			
				|  |  | --          // (role name) video_decoder.avc
 | 
	
		
			
				|  |  | --          // H.264 Main profile
 | 
	
		
			
				|  |  | --          decoder_name = OMX_H264HIGH_DECODER;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        default:
 | 
	
		
			
				|  |  | --          return false;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+      // H.264
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingAVC;
 | 
	
		
			
				|  |  | -+      m_pFormatName = "omx-h264";
 | 
	
		
			
				|  |  | -     break;
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_H263:
 | 
	
		
			
				|  |  | -     case AV_CODEC_ID_MPEG4:
 | 
	
		
			
				|  |  | --      // (role name) video_decoder.mpeg4
 | 
	
		
			
				|  |  | --      // MPEG-4, DivX 4/5 and Xvid compatible
 | 
	
		
			
				|  |  | --      decoder_name = OMX_MPEG4_DECODER;
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --    /*
 | 
	
		
			
				|  |  | --    TODO: what mpeg4 formats are "ext" ????
 | 
	
		
			
				|  |  | --    case NvxStreamType_MPEG4Ext:
 | 
	
		
			
				|  |  | --      // (role name) video_decoder.mpeg4
 | 
	
		
			
				|  |  | -       // MPEG-4, DivX 4/5 and Xvid compatible
 | 
	
		
			
				|  |  | --      decoder_name = OMX_MPEG4EXT_DECODER;
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingMPEG4;
 | 
	
		
			
				|  |  | -       m_pFormatName = "omx-mpeg4";
 | 
	
		
			
				|  |  | -     break;
 | 
	
		
			
				|  |  | --    */
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_MPEG1VIDEO:
 | 
	
		
			
				|  |  | -     case AV_CODEC_ID_MPEG2VIDEO:
 | 
	
		
			
				|  |  | --      // (role name) video_decoder.mpeg2
 | 
	
		
			
				|  |  | -       // MPEG-2
 | 
	
		
			
				|  |  | --      decoder_name = OMX_MPEG2V_DECODER;
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingMPEG2;
 | 
	
		
			
				|  |  | -+      m_pFormatName = "omx-mpeg2";
 | 
	
		
			
				|  |  | -+    break;
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_VP6:
 | 
	
		
			
				|  |  | -+      // this form is encoded upside down
 | 
	
		
			
				|  |  | -+      // fall through
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_VP6F:
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_VP6A:
 | 
	
		
			
				|  |  | -+      // VP6
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingVP6;
 | 
	
		
			
				|  |  | -+      m_pFormatName = "omx-vp6";
 | 
	
		
			
				|  |  | -+    break;
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_VP8:
 | 
	
		
			
				|  |  | -+      // VP8
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingVP8;
 | 
	
		
			
				|  |  | -+      m_pFormatName = "omx-vp8";
 | 
	
		
			
				|  |  | -+    break;
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_THEORA:
 | 
	
		
			
				|  |  | -+      // theora
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingTheora;
 | 
	
		
			
				|  |  | -+      m_pFormatName = "omx-theora";
 | 
	
		
			
				|  |  | -+    break;
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_MJPEG:
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_MJPEGB:
 | 
	
		
			
				|  |  | -+      // mjpg
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingMJPEG;
 | 
	
		
			
				|  |  | -+      m_pFormatName = "omx-mjpg";
 | 
	
		
			
				|  |  | -     break;
 | 
	
		
			
				|  |  | -     case AV_CODEC_ID_VC1:
 | 
	
		
			
				|  |  | --      // (role name) video_decoder.vc1
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_WMV3:
 | 
	
		
			
				|  |  | -       // VC-1, WMV9
 | 
	
		
			
				|  |  | --      decoder_name = OMX_VC1_DECODER;
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | -+      m_codingType = OMX_VIDEO_CodingWMV;
 | 
	
		
			
				|  |  | -+      m_pFormatName = "omx-vc1";
 | 
	
		
			
				|  |  | -+      break;
 | 
	
		
			
				|  |  | -     default:
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s : Video codec unknown: %x", CLASSNAME, __func__, hints.codec);
 | 
	
		
			
				|  |  | -       return false;
 | 
	
		
			
				|  |  | -     break;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // initialize OpenMAX.
 | 
	
		
			
				|  |  | --  if (!Initialize(decoder_name))
 | 
	
		
			
				|  |  | -+  if (!m_omx_decoder.Initialize("OMX.broadcom.video_decode", OMX_IndexParamVideoInit))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.Initialize", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // TODO: Find component from role name.
 | 
	
		
			
				|  |  | --  // Get the port information. This will obtain information about the
 | 
	
		
			
				|  |  | --  // number of ports and index of the first port.
 | 
	
		
			
				|  |  | --  OMX_PORT_PARAM_TYPE port_param;
 | 
	
		
			
				|  |  | --  OMX_INIT_STRUCTURE(port_param);
 | 
	
		
			
				|  |  | --  omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamVideoInit, &port_param);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    Deinitialize();
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  m_omx_input_port = port_param.nStartPortNumber;
 | 
	
		
			
				|  |  | --  m_omx_output_port = m_omx_input_port + 1;
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --    "%s::%s - decoder_component(0x%p), input_port(0x%x), output_port(0x%x)\n",
 | 
	
		
			
				|  |  | --    CLASSNAME, __func__, m_omx_decoder, m_omx_input_port, m_omx_output_port);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // TODO: Set role for the component because components could have multiple roles.
 | 
	
		
			
				|  |  | --  //QueryCodec();
 | 
	
		
			
				|  |  | -+  OMX_VIDEO_PARAM_PORTFORMATTYPE formatType;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(formatType);
 | 
	
		
			
				|  |  | -+  formatType.nPortIndex = m_omx_decoder.GetInputPort();
 | 
	
		
			
				|  |  | -+  formatType.eCompressionFormat = m_codingType;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.SetParameter(OMX_IndexParamVideoPortFormat, &formatType);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  OMX_PARAM_PORTDEFINITIONTYPE portParam;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(portParam);
 | 
	
		
			
				|  |  | -+  portParam.nPortIndex = m_omx_decoder.GetInputPort();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &portParam);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s error OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  portParam.nPortIndex = m_omx_decoder.GetInputPort();
 | 
	
		
			
				|  |  | -+  portParam.nBufferCountActual = 20;
 | 
	
		
			
				|  |  | -+  portParam.format.video.nFrameWidth  = m_decoded_width;
 | 
	
		
			
				|  |  | -+  portParam.format.video.nFrameHeight = m_decoded_height;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &portParam);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s error OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // request portsettingschanged on aspect ratio change
 | 
	
		
			
				|  |  | -+  OMX_CONFIG_REQUESTCALLBACKTYPE notifications;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(notifications);
 | 
	
		
			
				|  |  | -+  notifications.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | -+  notifications.nIndex = OMX_IndexParamBrcmPixelAspectRatio;
 | 
	
		
			
				|  |  | -+  notifications.bEnable = OMX_TRUE;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexConfigRequestCallback, ¬ifications);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s OMX_IndexConfigRequestCallback error (0%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (NaluFormatStartCodes(hints.codec, (uint8_t *)hints.extradata, hints.extrasize))
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    OMX_NALSTREAMFORMATTYPE nalStreamFormat;
 | 
	
		
			
				|  |  | -+    OMX_INIT_STRUCTURE(nalStreamFormat);
 | 
	
		
			
				|  |  | -+    nalStreamFormat.nPortIndex = m_omx_decoder.GetInputPort();
 | 
	
		
			
				|  |  | -+    nalStreamFormat.eNaluFormat = OMX_NaluFormatStartCodes;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexParamNalStreamFormatSelect, &nalStreamFormat);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s OMX_IndexParamNalStreamFormatSelect error (0%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // Component will be in OMX_StateLoaded now so we can alloc omx input/output buffers.
 | 
	
		
			
				|  |  | --  // we can only alloc them in OMX_StateLoaded state or if the component port is disabled
 | 
	
		
			
				|  |  | -   // Alloc buffers for the omx input port.
 | 
	
		
			
				|  |  | --  omx_err = AllocOMXInputBuffers();
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.AllocInputBuffers();
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    Deinitialize();
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s AllocInputBuffers error (0%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  // Alloc buffers for the omx output port.
 | 
	
		
			
				|  |  | --  m_egl_display = g_Windowing.GetEGLDisplay();
 | 
	
		
			
				|  |  | --  m_egl_context = g_Windowing.GetEGLContext();
 | 
	
		
			
				|  |  | --  omx_err = AllocOMXOutputBuffers();
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    FreeOMXInputBuffers(false);
 | 
	
		
			
				|  |  | --    Deinitialize();
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s error m_omx_decoder.SetStateForComponent error (0%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_is_open = true;
 | 
	
		
			
				|  |  | --  m_drop_state = false;
 | 
	
		
			
				|  |  | --  m_videoplayback_done = false;
 | 
	
		
			
				|  |  | -+  if (!SendDecoderConfig((uint8_t *)hints.extradata, hints.extrasize))
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // crank it up.
 | 
	
		
			
				|  |  | --  StartDecoder();
 | 
	
		
			
				|  |  | -+  m_drop_state = false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void COpenMaxVideo::Close()
 | 
	
		
			
				|  |  | -+void COpenMaxVideo::Dispose()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | --  if (m_omx_decoder)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if (m_omx_decoder_state != OMX_StateLoaded)
 | 
	
		
			
				|  |  | --      StopDecoder();
 | 
	
		
			
				|  |  | --    Deinitialize();
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  m_is_open = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COpenMaxVideo::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+#if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  if (m_drop_state != bDrop)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG, "%s::%s - m_drop_state(%d)",
 | 
	
		
			
				|  |  | -+      CLASSNAME, __func__, bDrop);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   m_drop_state = bDrop;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (m_drop_state)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::SendDecoderConfig(uint8_t *extradata, int extrasize)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  /* send decoder config */
 | 
	
		
			
				|  |  | -+  if (extrasize > 0 && extradata != NULL)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | -+    OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    // blow all but the last ready video frame
 | 
	
		
			
				|  |  | --    pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | --    while (m_omx_output_ready.size() > 1)
 | 
	
		
			
				|  |  | -+    if (omx_buffer == NULL)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      m_dts_queue.pop();
 | 
	
		
			
				|  |  | --      OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_output_ready.front()->omx_buffer;
 | 
	
		
			
				|  |  | --      m_omx_output_ready.pop();
 | 
	
		
			
				|  |  | --      // return the omx buffer back to OpenMax to fill.
 | 
	
		
			
				|  |  | --      omx_err = OMX_FillThisBuffer(m_omx_decoder, omx_buffer);
 | 
	
		
			
				|  |  | --      if (omx_err)
 | 
	
		
			
				|  |  | --        CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --          CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - buffer error 0x%08x", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "%s::%s - m_drop_state(%d)\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, m_drop_state);
 | 
	
		
			
				|  |  | --    #endif
 | 
	
		
			
				|  |  | -+    omx_buffer->nOffset = 0;
 | 
	
		
			
				|  |  | -+    omx_buffer->nFilledLen = extrasize;
 | 
	
		
			
				|  |  | -+    if (omx_buffer->nFilledLen > omx_buffer->nAllocLen)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - omx_buffer->nFilledLen > omx_buffer->nAllocLen", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    memcpy((unsigned char *)omx_buffer->pBuffer, extradata, omx_buffer->nFilledLen);
 | 
	
		
			
				|  |  | -+    omx_buffer->nFlags = OMX_BUFFERFLAG_CODECCONFIG | OMX_BUFFERFLAG_ENDOFFRAME;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+//CLog::Log(LOGINFO, "%s::%s - Empty(%d,%x)", CLASSNAME, __func__, omx_buffer->nFilledLen, omx_buffer->nFlags); CLog::MemDump((char *)omx_buffer->pBuffer, std::min(64U, omx_buffer->nFilledLen));
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  switch(codec)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    case AV_CODEC_ID_H264:
 | 
	
		
			
				|  |  | -+      if (extrasize < 7 || extradata == NULL)
 | 
	
		
			
				|  |  | -+        return true;
 | 
	
		
			
				|  |  | -+      // valid avcC atom data always starts with the value 1 (version), otherwise annexb
 | 
	
		
			
				|  |  | -+      else if ( *extradata != 1 )
 | 
	
		
			
				|  |  | -+        return true;
 | 
	
		
			
				|  |  | -+    default: break;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  return false;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if (pData)
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_port_settings_changed)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_PARAM_PORTDEFINITIONTYPE port_def;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(port_def);
 | 
	
		
			
				|  |  | -+  port_def.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_CONFIG_POINTTYPE pixel_aspect;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(pixel_aspect);
 | 
	
		
			
				|  |  | -+  pixel_aspect.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio, &pixel_aspect);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_port_settings_changed)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    int demuxer_bytes = iSize;
 | 
	
		
			
				|  |  | --    uint8_t *demuxer_content = pData;
 | 
	
		
			
				|  |  | -+    m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
 | 
	
		
			
				|  |  | -+    return true;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // convert in stripes
 | 
	
		
			
				|  |  | -+  port_def.format.video.nSliceHeight = 16;
 | 
	
		
			
				|  |  | -+  port_def.format.video.nStride = 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_CALLBACKTYPE callbacks = { NULL, NULL, DecoderFillBufferDoneCallback };
 | 
	
		
			
				|  |  | -+  if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit, &callbacks))
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_CONFIG_PORTBOOLEANTYPE discardMode;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(discardMode);
 | 
	
		
			
				|  |  | -+  discardMode.nPortIndex = m_omx_egl_render.GetInputPort();
 | 
	
		
			
				|  |  | -+  discardMode.bEnabled = OMX_FALSE;
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamBrcmVideoEGLRenderDiscardMode, &discardMode);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - error m_omx_egl_render.SetParameter(OMX_IndexParamBrcmVideoEGLRenderDiscardMode) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_omx_egl_render.ResetEos();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -+      port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight,
 | 
	
		
			
				|  |  | -+      port_def.format.video.xFramerate / (float)(1<<16), 0,0);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_omx_tunnel.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_tunnel.Establish();
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // Obtain the information about the output port.
 | 
	
		
			
				|  |  | -+  OMX_PARAM_PORTDEFINITIONTYPE port_format;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(port_format);
 | 
	
		
			
				|  |  | -+  port_format.nPortIndex = m_omx_egl_render.GetOutputPort();
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_egl_render.GetParameter(OMX_IndexParamPortDefinition, &port_format);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.GetParameter OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  port_format.nBufferCountActual = m_egl_buffer_count;
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_egl_render.SetParameter(OMX_IndexParamPortDefinition, &port_format);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.SetParameter OMX_IndexParamPortDefinition omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | -+    "%s::%s (1) - oport(%d), nFrameWidth(%u), nFrameHeight(%u), nStride(%x), nBufferCountMin(%u), nBufferCountActual(%u), nBufferSize(%u)",
 | 
	
		
			
				|  |  | -+    CLASSNAME, __func__, m_omx_egl_render.GetOutputPort(),
 | 
	
		
			
				|  |  | -+    port_format.format.video.nFrameWidth, port_format.format.video.nFrameHeight,port_format.format.video.nStride,
 | 
	
		
			
				|  |  | -+    port_format.nBufferCountMin, port_format.nBufferCountActual, port_format.nBufferSize);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    // we need to queue then de-queue the demux packet, seems silly but
 | 
	
		
			
				|  |  | --    // omx might not have a omx input buffer avaliable when we are called
 | 
	
		
			
				|  |  | --    // and we must store the demuxer packet and try again later.
 | 
	
		
			
				|  |  | -+  omx_err =  m_omx_egl_render.EnablePort(m_omx_egl_render.GetOutputPort(), false);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.EnablePort omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (!AllocOMXOutputBuffers())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - AllocOMXOutputBuffers failed", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_egl_render.WaitForCommand(OMX_CommandPortEnable, m_omx_egl_render.GetOutputPort());
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.WaitForCommand(OMX_CommandPortEnable) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  assert(m_omx_output_busy.empty());
 | 
	
		
			
				|  |  | -+  assert(m_omx_output_ready.empty());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.SetStateForComponent omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = PrimeFillBuffers();
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_egl_render.PrimeFillBuffers omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_port_settings_changed = true;
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %-8p %-6d dts:%.3f pts:%.3f demux_queue(%d) dts_queue(%d) ready_queue(%d) busy_queue(%d)",
 | 
	
		
			
				|  |  | -+     CLASSNAME, __func__, pData, iSize, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, m_demux_queue.size(), m_dts_queue.size(), m_omx_output_ready.size(), m_omx_output_busy.size());
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | -+  unsigned int demuxer_bytes = 0;
 | 
	
		
			
				|  |  | -+  uint8_t *demuxer_content = NULL;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // we need to queue then de-queue the demux packet, seems silly but
 | 
	
		
			
				|  |  | -+  // omx might not have a omx input buffer available when we are called
 | 
	
		
			
				|  |  | -+  // and we must store the demuxer packet and try again later.
 | 
	
		
			
				|  |  | -+  if (pData && m_demux_queue.empty() && m_omx_decoder.GetInputBufferSpace() >= (unsigned int)iSize)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    demuxer_bytes = iSize;
 | 
	
		
			
				|  |  | -+    demuxer_content = pData;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else if (pData && iSize)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -     omx_demux_packet demux_packet;
 | 
	
		
			
				|  |  | -     demux_packet.dts = dts;
 | 
	
		
			
				|  |  | -     demux_packet.pts = pts;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    demux_packet.size = demuxer_bytes;
 | 
	
		
			
				|  |  | --    demux_packet.buff = new OMX_U8[demuxer_bytes];
 | 
	
		
			
				|  |  | --    memcpy(demux_packet.buff, demuxer_content, demuxer_bytes);
 | 
	
		
			
				|  |  | -+    demux_packet.size = iSize;
 | 
	
		
			
				|  |  | -+    demux_packet.buff = new OMX_U8[iSize];
 | 
	
		
			
				|  |  | -+    memcpy(demux_packet.buff, pData, iSize);
 | 
	
		
			
				|  |  | -     m_demux_queue.push(demux_packet);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    // we can look at m_omx_input_avaliable.empty without needing to lock/unlock
 | 
	
		
			
				|  |  | -+  OMX_U8 *buffer_to_free = NULL;
 | 
	
		
			
				|  |  | -+  while (1)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -     // try to send any/all demux packets to omx decoder.
 | 
	
		
			
				|  |  | --    while (!m_omx_input_avaliable.empty() && !m_demux_queue.empty() )
 | 
	
		
			
				|  |  | -+    if (!demuxer_bytes && !m_demux_queue.empty())
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | --      OMX_BUFFERHEADERTYPE* omx_buffer;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      demux_packet = m_demux_queue.front();
 | 
	
		
			
				|  |  | --      m_demux_queue.pop();
 | 
	
		
			
				|  |  | --      // need to lock here to retreve an input buffer and pop the queue
 | 
	
		
			
				|  |  | --      pthread_mutex_lock(&m_omx_input_mutex);
 | 
	
		
			
				|  |  | --      omx_buffer = m_omx_input_avaliable.front();
 | 
	
		
			
				|  |  | --      m_omx_input_avaliable.pop();
 | 
	
		
			
				|  |  | --      pthread_mutex_unlock(&m_omx_input_mutex);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      // delete the previous demuxer buffer
 | 
	
		
			
				|  |  | --      delete [] omx_buffer->pBuffer;
 | 
	
		
			
				|  |  | --      // setup a new omx_buffer.
 | 
	
		
			
				|  |  | --      omx_buffer->nFlags  = m_omx_input_eos ? OMX_BUFFERFLAG_EOS : 0;
 | 
	
		
			
				|  |  | -+      omx_demux_packet &demux_packet = m_demux_queue.front();
 | 
	
		
			
				|  |  | -+      if (m_omx_decoder.GetInputBufferSpace() >= (unsigned int)demux_packet.size)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        // need to lock here to retrieve an input buffer and pop the queue
 | 
	
		
			
				|  |  | -+        m_demux_queue.pop();
 | 
	
		
			
				|  |  | -+        demuxer_bytes = (unsigned int)demux_packet.size;
 | 
	
		
			
				|  |  | -+        demuxer_content = demux_packet.buff;
 | 
	
		
			
				|  |  | -+        buffer_to_free = demux_packet.buff;
 | 
	
		
			
				|  |  | -+        dts = demux_packet.dts;
 | 
	
		
			
				|  |  | -+        pts = demux_packet.pts;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (demuxer_content)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      // 500ms timeout
 | 
	
		
			
				|  |  | -+      OMX_BUFFERHEADERTYPE *omx_buffer = m_omx_decoder.GetInputBuffer(500);
 | 
	
		
			
				|  |  | -+      if (omx_buffer == NULL)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s - m_omx_decoder.GetInputBuffer timeout", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+        return VC_ERROR;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+      //CLog::Log(LOGDEBUG, "%s::%s - omx_buffer=%p", CLASSNAME, __func__, omx_buffer);
 | 
	
		
			
				|  |  | -+      #endif
 | 
	
		
			
				|  |  | -+      omx_buffer->nFlags  = 0;
 | 
	
		
			
				|  |  | -       omx_buffer->nOffset = 0;
 | 
	
		
			
				|  |  | --      omx_buffer->pBuffer = demux_packet.buff;
 | 
	
		
			
				|  |  | --      omx_buffer->nAllocLen  = demux_packet.size;
 | 
	
		
			
				|  |  | --      omx_buffer->nFilledLen = demux_packet.size;
 | 
	
		
			
				|  |  | --      omx_buffer->nTimeStamp = (demux_packet.pts == DVD_NOPTS_VALUE) ? 0 : demux_packet.pts * 1000.0; // in microseconds;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
 | 
	
		
			
				|  |  | -+      omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts);
 | 
	
		
			
				|  |  | -       omx_buffer->pAppPrivate = omx_buffer;
 | 
	
		
			
				|  |  | --      omx_buffer->nInputPortIndex = m_omx_input_port;
 | 
	
		
			
				|  |  | -+      memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      #if defined(OMX_DEBUG_EMPTYBUFFERDONE)
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --        "%s::%s - feeding decoder, omx_buffer->pBuffer(0x%p), demuxer_bytes(%d)\n",
 | 
	
		
			
				|  |  | --        CLASSNAME, __func__, omx_buffer->pBuffer, demuxer_bytes);
 | 
	
		
			
				|  |  | --      #endif
 | 
	
		
			
				|  |  | --      // Give this omx_buffer to OpenMax to be decoded.
 | 
	
		
			
				|  |  | --      omx_err = OMX_EmptyThisBuffer(m_omx_decoder, omx_buffer);
 | 
	
		
			
				|  |  | --      if (omx_err)
 | 
	
		
			
				|  |  | -+      demuxer_bytes -= omx_buffer->nFilledLen;
 | 
	
		
			
				|  |  | -+      demuxer_content += omx_buffer->nFilledLen;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      if (demuxer_bytes == 0)
 | 
	
		
			
				|  |  | -+        omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
 | 
	
		
			
				|  |  | -+      if (pts == DVD_NOPTS_VALUE)
 | 
	
		
			
				|  |  | -+        omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
 | 
	
		
			
				|  |  | -+      if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
 | 
	
		
			
				|  |  | -+        omx_buffer->nFlags |= OMX_BUFFERFLAG_DATACORRUPT;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x",
 | 
	
		
			
				|  |  | -+        CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
 | 
	
		
			
				|  |  | -+      if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --          "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)\n",
 | 
	
		
			
				|  |  | --          CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s - OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -         return VC_ERROR;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --      // only push if we are successful with feeding OMX_EmptyThisBuffer
 | 
	
		
			
				|  |  | --      m_dts_queue.push(demux_packet.dts);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      // if m_omx_input_avaliable and/or demux_queue are now empty,
 | 
	
		
			
				|  |  | --      // wait up to 20ms for OpenMax to consume a demux packet
 | 
	
		
			
				|  |  | --      if (m_omx_input_avaliable.empty() || m_demux_queue.empty())
 | 
	
		
			
				|  |  | --        m_input_consumed_event.WaitMSec(1);
 | 
	
		
			
				|  |  | -+      if (demuxer_bytes == 0)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+#ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -+        // only push if we are successful with feeding OMX_EmptyThisBuffer
 | 
	
		
			
				|  |  | -+        m_dts_queue.push(dts);
 | 
	
		
			
				|  |  | -+        assert(m_dts_queue.size() < 32);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+        if (buffer_to_free)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          delete [] buffer_to_free;
 | 
	
		
			
				|  |  | -+          buffer_to_free = NULL;
 | 
	
		
			
				|  |  | -+          demuxer_content = NULL;
 | 
	
		
			
				|  |  | -+          continue;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_decoder.WaitForEvent(OMX_EventPortSettingsChanged, 0);
 | 
	
		
			
				|  |  | -+    if (omx_err == OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      if (!PortSettingsChanged())
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        return VC_ERROR;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if (omx_err != OMX_ErrorTimeout)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - video not supported omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return VC_ERROR;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    if (m_omx_input_avaliable.empty() && !m_demux_queue.empty())
 | 
	
		
			
				|  |  | --      m_input_consumed_event.WaitMSec(1);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --    if (m_omx_input_avaliable.empty())
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --        "%s::%s - buffering demux, m_demux_queue_size(%d), demuxer_bytes(%d)\n",
 | 
	
		
			
				|  |  | --        CLASSNAME, __func__, m_demux_queue.size(), demuxer_bytes);
 | 
	
		
			
				|  |  | --    #endif
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_decoder.WaitForEvent(OMX_EventParamOrConfigChanged, 0);
 | 
	
		
			
				|  |  | -+    if (omx_err == OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      if (!PortSettingsChanged())
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s - error PortSettingsChanged (EventParamOrConfigChanged) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        return VC_ERROR;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if (omx_err == OMX_ErrorStreamCorrupt)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - video not supported 2 omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return VC_ERROR;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    if (!demuxer_bytes)
 | 
	
		
			
				|  |  | -+      break;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  if (!m_omx_decoder.GetInputBufferSpace())
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | -+      "%s::%s - buffering demux, m_demux_queue_size(%d), demuxer_bytes(%d) m_dts_queue.size(%d)",
 | 
	
		
			
				|  |  | -+      CLASSNAME, __func__, m_demux_queue.size(), demuxer_bytes, m_dts_queue.size());
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   if (m_omx_output_ready.empty())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    //CLog::Log(LOGDEBUG, "%s::%s - empty: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size());
 | 
	
		
			
				|  |  | -     return VC_BUFFER;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  return VC_PICTURE | VC_BUFFER;
 | 
	
		
			
				|  |  | -+  //CLog::Log(LOGDEBUG, "%s::%s -  full: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size());
 | 
	
		
			
				|  |  | -+  return VC_PICTURE;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COpenMaxVideo::Reset(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | --  // only reset OpenMax decoder if it's running
 | 
	
		
			
				|  |  | --  if (m_omx_decoder_state == OMX_StateExecuting)
 | 
	
		
			
				|  |  | -+  m_omx_egl_render.FlushAll();
 | 
	
		
			
				|  |  | -+  m_omx_decoder.FlushAll();
 | 
	
		
			
				|  |  | -+  // blow all ready video frames
 | 
	
		
			
				|  |  | -+  while (!m_omx_output_ready.empty())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_err = StopDecoder();
 | 
	
		
			
				|  |  | --    // Alloc OpenMax input buffers.
 | 
	
		
			
				|  |  | --    omx_err = AllocOMXInputBuffers();
 | 
	
		
			
				|  |  | --    // Alloc OpenMax output buffers.
 | 
	
		
			
				|  |  | --    omx_err = AllocOMXOutputBuffers();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_err = StartDecoder();
 | 
	
		
			
				|  |  | -+    pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+    COpenMaxVideoBuffer *pic = m_omx_output_ready.front();
 | 
	
		
			
				|  |  | -+    m_omx_output_ready.pop();
 | 
	
		
			
				|  |  | -+    pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+    // return the omx buffer back to OpenMax to fill.
 | 
	
		
			
				|  |  | -+    ReturnOpenMaxBuffer(pic);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --*/
 | 
	
		
			
				|  |  | --  ::Sleep(100);
 | 
	
		
			
				|  |  | -+#ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -+  while (!m_dts_queue.empty())
 | 
	
		
			
				|  |  | -+    m_dts_queue.pop();
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  while (!m_demux_queue.empty())
 | 
	
		
			
				|  |  | -+    m_demux_queue.pop();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+OMX_ERRORTYPE COpenMaxVideo::ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  while (m_omx_output_busy.size() > 1)
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+#if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %p (%d)", CLASSNAME, __func__, buffer, m_omx_output_busy.size());
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+  bool done = buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_EOS;
 | 
	
		
			
				|  |  | -+  if (!done)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    // fetch a output buffer and pop it off the busy list
 | 
	
		
			
				|  |  | --    pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | --    OpenMaxVideoBuffer *buffer = m_omx_output_busy.front();
 | 
	
		
			
				|  |  | --    m_omx_output_busy.pop();
 | 
	
		
			
				|  |  | --    pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+    // return the omx buffer back to OpenMax to fill.
 | 
	
		
			
				|  |  | -+    buffer->omx_buffer->nFlags = 0;
 | 
	
		
			
				|  |  | -+    buffer->omx_buffer->nFilledLen = 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    bool done = buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_EOS;
 | 
	
		
			
				|  |  | --    if (!done)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      // return the omx buffer back to OpenMax to fill.
 | 
	
		
			
				|  |  | --      OMX_ERRORTYPE omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer);
 | 
	
		
			
				|  |  | --      if (omx_err)
 | 
	
		
			
				|  |  | --        CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --          CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    assert(buffer->omx_buffer->nOutputPortIndex == m_omx_egl_render.GetOutputPort());
 | 
	
		
			
				|  |  | -+#if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG, "%s::%s FillThisBuffer(%p) %p->%ld", CLASSNAME, __func__, buffer, buffer->omx_buffer, buffer->m_refs);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+    OMX_ERRORTYPE omx_err = m_omx_egl_render.FillThisBuffer(buffer->omx_buffer);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (omx_err)
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer, omx_err(0x%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  return omx_err;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void COpenMaxVideo::ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  // remove from busy list
 | 
	
		
			
				|  |  | -+  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  m_omx_output_busy.erase(std::remove(m_omx_output_busy.begin(), m_omx_output_busy.end(), buffer), m_omx_output_busy.end());
 | 
	
		
			
				|  |  | -+  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  ReturnOpenMaxBuffer(buffer);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  //CLog::Log(LOGDEBUG, "%s::%s - m_omx_output_busy.size()=%d m_omx_output_ready.size()=%d", CLASSNAME, __func__, m_omx_output_busy.size(), m_omx_output_ready.size());
 | 
	
		
			
				|  |  | -+  //CLog::Log(LOGDEBUG, "%s::%s -  full: buffers:%d", CLASSNAME, __func__, m_omx_output_ready.size());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (!m_omx_output_ready.empty())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    OpenMaxVideoBuffer *buffer;
 | 
	
		
			
				|  |  | -+    COpenMaxVideoBuffer *buffer;
 | 
	
		
			
				|  |  | -     // fetch a output buffer and pop it off the ready list
 | 
	
		
			
				|  |  | -     pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -     buffer = m_omx_output_ready.front();
 | 
	
		
			
				|  |  | -     m_omx_output_ready.pop();
 | 
	
		
			
				|  |  | --    m_omx_output_busy.push(buffer);
 | 
	
		
			
				|  |  | -+    m_omx_output_busy.push_back(buffer);
 | 
	
		
			
				|  |  | -     pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture);
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->dts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->format = RENDER_FMT_OMXEGL;
 | 
	
		
			
				|  |  | --    pDvdVideoPicture->openMax = this;
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->openMaxBuffer = buffer;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->color_range  = 0;
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->color_matrix = 4;
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->iWidth  = m_decoded_width;
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->iHeight = m_decoded_height;
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->iDisplayWidth  = m_decoded_width;
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->iDisplayHeight = m_decoded_height;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -     if (!m_dts_queue.empty())
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       pDvdVideoPicture->dts = m_dts_queue.front();
 | 
	
		
			
				|  |  | -       m_dts_queue.pop();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -     // nTimeStamp is in microseconds
 | 
	
		
			
				|  |  | --    pDvdVideoPicture->pts = (buffer->omx_buffer->nTimeStamp == 0) ? DVD_NOPTS_VALUE : (double)buffer->omx_buffer->nTimeStamp / 1000.0;
 | 
	
		
			
				|  |  | -+    double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->pts = (ts == 0) ? DVD_NOPTS_VALUE : ts;
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->openMaxBuffer->Acquire();
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->iFlags  = DVP_FLAG_ALLOCATED;
 | 
	
		
			
				|  |  | -+    if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT)
 | 
	
		
			
				|  |  | -+      pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
 | 
	
		
			
				|  |  | -+#if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -+        pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6,
 | 
	
		
			
				|  |  | -+        pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "%s::%s - called but m_omx_output_ready is empty\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - called but m_omx_output_ready is empty", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  pDvdVideoPicture->iFlags  = DVP_FLAG_ALLOCATED;
 | 
	
		
			
				|  |  | --  pDvdVideoPicture->iFlags |= m_drop_state ? DVP_FLAG_DROPPED : 0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// DecoderEmptyBufferDone -- OpenMax input buffer has been emptied
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::DecoderEmptyBufferDone(
 | 
	
		
			
				|  |  | --  OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | --  OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --  OMX_BUFFERHEADERTYPE* pBuffer)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  COpenMaxVideo *ctx = static_cast<COpenMaxVideo*>(pAppData);
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_EMPTYBUFFERDONE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n",
 | 
	
		
			
				|  |  | --    CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --*/
 | 
	
		
			
				|  |  | --  // queue free input buffer to avaliable list.
 | 
	
		
			
				|  |  | --  pthread_mutex_lock(&ctx->m_omx_input_mutex);
 | 
	
		
			
				|  |  | --  ctx->m_omx_input_avaliable.push(pBuffer);
 | 
	
		
			
				|  |  | --  ctx->m_input_consumed_event.Set();
 | 
	
		
			
				|  |  | --  pthread_mutex_unlock(&ctx->m_omx_input_mutex);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+#if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %p", CLASSNAME, __func__, pDvdVideoPicture->openMaxBuffer);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+  if (pDvdVideoPicture->format == RENDER_FMT_OMXEGL)
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->openMaxBuffer->Release();
 | 
	
		
			
				|  |  | -+  memset(pDvdVideoPicture, 0, sizeof *pDvdVideoPicture);
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --// DecoderFillBufferDone -- OpenMax output buffer has been filled
 | 
	
		
			
				|  |  | -+  // DecoderFillBufferDone -- OpenMax output buffer has been filled
 | 
	
		
			
				|  |  | - OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
 | 
	
		
			
				|  |  | -   OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | --  OMX_PTR pAppData,
 | 
	
		
			
				|  |  | -   OMX_BUFFERHEADERTYPE* pBuffer)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  COpenMaxVideo *ctx = static_cast<COpenMaxVideo*>(pAppData);
 | 
	
		
			
				|  |  | --  OpenMaxVideoBuffer *buffer = (OpenMaxVideoBuffer*)pBuffer->pAppPrivate;
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_FILLBUFFERDONE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - buffer_size(%lu), timestamp(%f)\n",
 | 
	
		
			
				|  |  | --    CLASSNAME, __func__, pBuffer->nFilledLen, (double)pBuffer->nTimeStamp / 1000.0);
 | 
	
		
			
				|  |  | -+  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f",
 | 
	
		
			
				|  |  | -+    CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (!ctx->m_portChanging)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    // queue output omx buffer to ready list.
 | 
	
		
			
				|  |  | --    pthread_mutex_lock(&ctx->m_omx_output_mutex);
 | 
	
		
			
				|  |  | --    ctx->m_omx_output_ready.push(buffer);
 | 
	
		
			
				|  |  | --    pthread_mutex_unlock(&ctx->m_omx_output_mutex);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+  // queue output omx buffer to ready list.
 | 
	
		
			
				|  |  | -+  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  m_omx_output_ready.push(buffer);
 | 
	
		
			
				|  |  | -+  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   return OMX_ErrorNone;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void COpenMaxVideo::QueryCodec(void)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --  OMX_VIDEO_PARAM_PROFILELEVELTYPE port_param;
 | 
	
		
			
				|  |  | --  OMX_INIT_STRUCTURE(port_param);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  port_param.nPortIndex = m_omx_input_port;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  for (port_param.nProfileIndex = 0;; port_param.nProfileIndex++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    omx_err = OMX_GetParameter(m_omx_decoder,
 | 
	
		
			
				|  |  | --      OMX_IndexParamVideoProfileLevelQuerySupported, &port_param);
 | 
	
		
			
				|  |  | --    if (omx_err)
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_codec_capability omx_capability;
 | 
	
		
			
				|  |  | --    omx_capability.level = port_param.eLevel;
 | 
	
		
			
				|  |  | --    omx_capability.profile = port_param.eProfile;
 | 
	
		
			
				|  |  | --    m_omx_decoder_capabilities.push_back(omx_capability);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - OMX_ERRORTYPE COpenMaxVideo::PrimeFillBuffers(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --  OpenMaxVideoBuffer *buffer;
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer *buffer;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | -   // tell OpenMax to start filling output buffers
 | 
	
		
			
				|  |  | -   for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     buffer = m_omx_output_buffers[i];
 | 
	
		
			
				|  |  | -     // always set the port index.
 | 
	
		
			
				|  |  | --    buffer->omx_buffer->nOutputPortIndex = m_omx_output_port;
 | 
	
		
			
				|  |  | --    // Need to clear the EOS flag.
 | 
	
		
			
				|  |  | --    buffer->omx_buffer->nFlags &= ~OMX_BUFFERFLAG_EOS;
 | 
	
		
			
				|  |  | -+    buffer->omx_buffer->nOutputPortIndex = m_omx_egl_render.GetOutputPort();
 | 
	
		
			
				|  |  | -     buffer->omx_buffer->pAppPrivate = buffer;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_err = OMX_FillThisBuffer(m_omx_decoder, buffer->omx_buffer);
 | 
	
		
			
				|  |  | --    if (omx_err)
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s - OMX_FillThisBuffer failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --        CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    omx_err = ReturnOpenMaxBuffer(buffer);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   return omx_err;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::AllocOMXInputBuffers(void)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // Obtain the information about the decoder input port.
 | 
	
		
			
				|  |  | --  OMX_PARAM_PORTDEFINITIONTYPE port_format;
 | 
	
		
			
				|  |  | --  OMX_INIT_STRUCTURE(port_format);
 | 
	
		
			
				|  |  | --  port_format.nPortIndex = m_omx_input_port;
 | 
	
		
			
				|  |  | --  OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --    "%s::%s - iport(%d), nBufferCountMin(%lu), nBufferSize(%lu)\n",
 | 
	
		
			
				|  |  | --    CLASSNAME, __func__, m_omx_input_port, port_format.nBufferCountMin, port_format.nBufferSize);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --  for (size_t i = 0; i < port_format.nBufferCountMin; i++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    OMX_BUFFERHEADERTYPE *buffer = NULL;
 | 
	
		
			
				|  |  | --    // use an external buffer that's sized according to actual demux
 | 
	
		
			
				|  |  | --    // packet size, start at internal's buffer size, will get deleted when
 | 
	
		
			
				|  |  | --    // we start pulling demuxer packets and using demux packet sized buffers.
 | 
	
		
			
				|  |  | --    OMX_U8* data = new OMX_U8[port_format.nBufferSize];
 | 
	
		
			
				|  |  | --    omx_err = OMX_UseBuffer(m_omx_decoder, &buffer, m_omx_input_port, NULL, port_format.nBufferSize, data);
 | 
	
		
			
				|  |  | --    if (omx_err)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s - OMX_UseBuffer failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --        CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --      return(omx_err);
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    m_omx_input_buffers.push_back(buffer);
 | 
	
		
			
				|  |  | --    // don't have to lock/unlock here, we are not decoding
 | 
	
		
			
				|  |  | --    m_omx_input_avaliable.push(buffer);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  m_omx_input_eos = false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return(omx_err);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(bool wait)
 | 
	
		
			
				|  |  | -+OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  /*
 | 
	
		
			
				|  |  | --  omx_err = OMX_SendCommand(m_omx_decoder, OMX_CommandFlush, m_omx_input_port, 0);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s - OMX_CommandFlush failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --  else if (wait)
 | 
	
		
			
				|  |  | --    sem_wait(m_omx_flush_input);
 | 
	
		
			
				|  |  | --  */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // free omx input port buffers.
 | 
	
		
			
				|  |  | --  for (size_t i = 0; i < m_omx_input_buffers.size(); i++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    // using external buffers (OMX_UseBuffer), free our external buffers
 | 
	
		
			
				|  |  | --    //  before calling OMX_FreeBuffer which frees the omx buffer.
 | 
	
		
			
				|  |  | --    delete [] m_omx_input_buffers[i]->pBuffer;
 | 
	
		
			
				|  |  | --    m_omx_input_buffers[i]->pBuffer = NULL;
 | 
	
		
			
				|  |  | --    omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_input_port, m_omx_input_buffers[i]);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  m_omx_input_buffers.clear();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   // empty input buffer queue. not decoding so don't need lock/unlock.
 | 
	
		
			
				|  |  | --  while (!m_omx_input_avaliable.empty())
 | 
	
		
			
				|  |  | --    m_omx_input_avaliable.pop();
 | 
	
		
			
				|  |  | -   while (!m_demux_queue.empty())
 | 
	
		
			
				|  |  | -     m_demux_queue.pop();
 | 
	
		
			
				|  |  | -+#ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -   while (!m_dts_queue.empty())
 | 
	
		
			
				|  |  | -     m_dts_queue.pop();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   return(omx_err);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
 | 
	
		
			
				|  |  | --  omx->AllocOMXOutputEGLTextures();
 | 
	
		
			
				|  |  | -+  return omx->AllocOMXOutputEGLTextures() == OMX_ErrorNone;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
 | 
	
		
			
				|  |  | --  omx->FreeOMXOutputEGLTextures(true);
 | 
	
		
			
				|  |  | -+  return omx->FreeOMXOutputEGLTextures() == OMX_ErrorNone;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputBuffers(void)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::AllocOMXOutputBuffers(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if ( g_application.IsCurrentThread() )
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    omx_err = AllocOMXOutputEGLTextures();
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    ThreadMessageCallback callbackData;
 | 
	
		
			
				|  |  | --    callbackData.callback = &CallbackAllocOMXEGLTextures;
 | 
	
		
			
				|  |  | --    callbackData.userptr = (void *)this;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    ThreadMessage tMsg;
 | 
	
		
			
				|  |  | --    tMsg.dwMessage = TMSG_CALLBACK;
 | 
	
		
			
				|  |  | --    tMsg.lpVoid = (void*)&callbackData;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    g_application.getApplicationMessenger().SendMessage(tMsg, true);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return omx_err;
 | 
	
		
			
				|  |  | -+  return g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputBuffers(bool wait)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::FreeOMXOutputBuffers(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err = FreeOMXOutputEGLTextures(wait);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return omx_err;
 | 
	
		
			
				|  |  | -+  return g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (!eglCreateImageKHR)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    GETEXTENSION(PFNEGLCREATEIMAGEKHRPROC,  eglCreateImageKHR);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -   EGLint attrib = EGL_NONE;
 | 
	
		
			
				|  |  | --  OpenMaxVideoBuffer *egl_buffer;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // Obtain the information about the output port.
 | 
	
		
			
				|  |  | --  OMX_PARAM_PORTDEFINITIONTYPE port_format;
 | 
	
		
			
				|  |  | --  OMX_INIT_STRUCTURE(port_format);
 | 
	
		
			
				|  |  | --  port_format.nPortIndex = m_omx_output_port;
 | 
	
		
			
				|  |  | --  omx_err = OMX_GetParameter(m_omx_decoder, OMX_IndexParamPortDefinition, &port_format);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --    "%s::%s (1) - oport(%d), nFrameWidth(%lu), nFrameHeight(%lu), nStride(%lx), nBufferCountMin(%lu), nBufferSize(%lu)\n",
 | 
	
		
			
				|  |  | --    CLASSNAME, __func__, m_omx_output_port,
 | 
	
		
			
				|  |  | --    port_format.format.video.nFrameWidth, port_format.format.video.nFrameHeight,port_format.format.video.nStride,
 | 
	
		
			
				|  |  | --    port_format.nBufferCountMin, port_format.nBufferSize);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer *egl_buffer;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   glActiveTexture(GL_TEXTURE0);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  for (size_t i = 0; i < port_format.nBufferCountMin; i++)
 | 
	
		
			
				|  |  | -+  for (size_t i = 0; i < m_egl_buffer_count; i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    egl_buffer = new OpenMaxVideoBuffer;
 | 
	
		
			
				|  |  | --    memset(egl_buffer, 0, sizeof(*egl_buffer));
 | 
	
		
			
				|  |  | -+    egl_buffer = new COpenMaxVideoBuffer(this);
 | 
	
		
			
				|  |  | -     egl_buffer->width  = m_decoded_width;
 | 
	
		
			
				|  |  | -     egl_buffer->height = m_decoded_height;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     glGenTextures(1, &egl_buffer->texture_id);
 | 
	
		
			
				|  |  | -     glBindTexture(GL_TEXTURE_2D, egl_buffer->texture_id);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    // no mipmaps
 | 
	
		
			
				|  |  | -+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
	
		
			
				|  |  | -+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     // create space for buffer with a texture
 | 
	
		
			
				|  |  | -     glTexImage2D(
 | 
	
		
			
				|  |  | -       GL_TEXTURE_2D,      // target
 | 
	
		
			
				|  |  | -@@ -710,8 +928,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | -       GL_RGBA,            // format
 | 
	
		
			
				|  |  | -       GL_UNSIGNED_BYTE,   // type
 | 
	
		
			
				|  |  | -       NULL);              // pixels -- will be provided later
 | 
	
		
			
				|  |  | --      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
	
		
			
				|  |  | --      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     // create EGLImage from texture
 | 
	
		
			
				|  |  | -     egl_buffer->egl_image = eglCreateImageKHR(
 | 
	
		
			
				|  |  | -@@ -722,49 +938,40 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | -       &attrib);
 | 
	
		
			
				|  |  | -     if (!egl_buffer->egl_image)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -       return(OMX_ErrorUndefined);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     egl_buffer->index = i;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     // tell decoder output port that it will be using EGLImage
 | 
	
		
			
				|  |  | --    omx_err = OMX_UseEGLImage(
 | 
	
		
			
				|  |  | --      m_omx_decoder, &egl_buffer->omx_buffer, m_omx_output_port, egl_buffer, egl_buffer->egl_image);
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_egl_render.UseEGLImage(
 | 
	
		
			
				|  |  | -+      &egl_buffer->omx_buffer, m_omx_egl_render.GetOutputPort(), egl_buffer, egl_buffer->egl_image);
 | 
	
		
			
				|  |  | -     if (omx_err)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s - OMX_UseEGLImage failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - OMX_UseEGLImage failed with omx_err(0x%x)",
 | 
	
		
			
				|  |  | -         CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -       return(omx_err);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     m_omx_output_buffers.push_back(egl_buffer);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d\n",
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d",
 | 
	
		
			
				|  |  | -       CLASSNAME, __func__, egl_buffer->egl_image, egl_buffer->width, egl_buffer->height);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  m_omx_output_eos = false;
 | 
	
		
			
				|  |  | --  while (!m_omx_output_busy.empty())
 | 
	
		
			
				|  |  | --    m_omx_output_busy.pop();
 | 
	
		
			
				|  |  | --  while (!m_omx_output_ready.empty())
 | 
	
		
			
				|  |  | --    m_omx_output_ready.pop();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   return omx_err;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(bool wait)
 | 
	
		
			
				|  |  | -+OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --  OpenMaxVideoBuffer *egl_buffer;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (!eglDestroyImageKHR)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    GETEXTENSION(PFNEGLDESTROYIMAGEKHRPROC, eglDestroyImageKHR);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer *egl_buffer;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     egl_buffer = m_omx_output_buffers[i];
 | 
	
		
			
				|  |  | -     // tell decoder output port to stop using the EGLImage
 | 
	
		
			
				|  |  | --    omx_err = OMX_FreeBuffer(m_omx_decoder, m_omx_output_port, egl_buffer->omx_buffer);
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_egl_render.FreeOutputBuffer(egl_buffer->omx_buffer);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.FreeOutputBuffer(%p) omx_err(0x%08x)", CLASSNAME, __func__, egl_buffer->omx_buffer, omx_err);
 | 
	
		
			
				|  |  | -     // destroy egl_image
 | 
	
		
			
				|  |  | -     eglDestroyImageKHR(m_egl_display, egl_buffer->egl_image);
 | 
	
		
			
				|  |  | -     // free texture
 | 
	
		
			
				|  |  | -@@ -777,274 +984,45 @@ OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(bool wait)
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --// DecoderEventHandler -- OMX event callback
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::DecoderEventHandler(
 | 
	
		
			
				|  |  | --  OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | --  OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --  OMX_EVENTTYPE eEvent,
 | 
	
		
			
				|  |  | --  OMX_U32 nData1,
 | 
	
		
			
				|  |  | --  OMX_U32 nData2,
 | 
	
		
			
				|  |  | --  OMX_PTR pEventData)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | --  COpenMaxVideo *ctx = static_cast<COpenMaxVideo*>(pAppData);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --    "COpenMax::%s - hComponent(0x%p), eEvent(0x%x), nData1(0x%lx), nData2(0x%lx), pEventData(0x%p)\n",
 | 
	
		
			
				|  |  | --    __func__, hComponent, eEvent, nData1, nData2, pEventData);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --*/
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  switch (eEvent)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    case OMX_EventCmdComplete:
 | 
	
		
			
				|  |  | --      switch(nData1)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        case OMX_CommandStateSet:
 | 
	
		
			
				|  |  | --          ctx->m_omx_decoder_state = (int)nData2;
 | 
	
		
			
				|  |  | --          switch (ctx->m_omx_decoder_state)
 | 
	
		
			
				|  |  | --          {
 | 
	
		
			
				|  |  | --            case OMX_StateInvalid:
 | 
	
		
			
				|  |  | --              CLog::Log(LOGDEBUG, "%s::%s - OMX_StateInvalid\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --            case OMX_StateLoaded:
 | 
	
		
			
				|  |  | --              CLog::Log(LOGDEBUG, "%s::%s - OMX_StateLoaded\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --            case OMX_StateIdle:
 | 
	
		
			
				|  |  | --              CLog::Log(LOGDEBUG, "%s::%s - OMX_StateIdle\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --            case OMX_StateExecuting:
 | 
	
		
			
				|  |  | --              CLog::Log(LOGDEBUG, "%s::%s - OMX_StateExecuting\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --            case OMX_StatePause:
 | 
	
		
			
				|  |  | --              CLog::Log(LOGDEBUG, "%s::%s - OMX_StatePause\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --            case OMX_StateWaitForResources:
 | 
	
		
			
				|  |  | --              CLog::Log(LOGDEBUG, "%s::%s - OMX_StateWaitForResources\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --            default:
 | 
	
		
			
				|  |  | --              CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --                "%s::%s - Unknown OMX_Statexxxxx, state(%d)\n",
 | 
	
		
			
				|  |  | --                CLASSNAME, __func__, ctx->m_omx_decoder_state);
 | 
	
		
			
				|  |  | --            break;
 | 
	
		
			
				|  |  | --          }
 | 
	
		
			
				|  |  | --          sem_post(ctx->m_omx_decoder_state_change);
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case OMX_CommandFlush:
 | 
	
		
			
				|  |  | --          /*
 | 
	
		
			
				|  |  | --          if (OMX_ALL == (int)nData2)
 | 
	
		
			
				|  |  | --          {
 | 
	
		
			
				|  |  | --            sem_post(ctx->m_omx_flush_input);
 | 
	
		
			
				|  |  | --            sem_post(ctx->m_omx_flush_output);
 | 
	
		
			
				|  |  | --            CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input/output\n",__func__);
 | 
	
		
			
				|  |  | --          }
 | 
	
		
			
				|  |  | --          else if (ctx->m_omx_input_port == (int)nData2)
 | 
	
		
			
				|  |  | --          {
 | 
	
		
			
				|  |  | --            sem_post(ctx->m_omx_flush_input);
 | 
	
		
			
				|  |  | --            CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush input\n",__func__);
 | 
	
		
			
				|  |  | --          }
 | 
	
		
			
				|  |  | --          else if (ctx->m_omx_output_port == (int)nData2)
 | 
	
		
			
				|  |  | --          {
 | 
	
		
			
				|  |  | --            sem_post(ctx->m_omx_flush_output);
 | 
	
		
			
				|  |  | --            CLog::Log(LOGDEBUG, "COpenMax::%s - OMX_CommandFlush ouput\n",__func__);
 | 
	
		
			
				|  |  | --          }
 | 
	
		
			
				|  |  | --          else
 | 
	
		
			
				|  |  | --          */
 | 
	
		
			
				|  |  | --          {
 | 
	
		
			
				|  |  | --            #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --            CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --              "%s::%s - OMX_CommandFlush, nData2(0x%lx)\n",
 | 
	
		
			
				|  |  | --              CLASSNAME, __func__, nData2);
 | 
	
		
			
				|  |  | --            #endif
 | 
	
		
			
				|  |  | --          }
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case OMX_CommandPortDisable:
 | 
	
		
			
				|  |  | --          #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --          CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --            "%s::%s - OMX_CommandPortDisable, nData1(0x%lx), nData2(0x%lx)\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__, nData1, nData2);
 | 
	
		
			
				|  |  | --          #endif
 | 
	
		
			
				|  |  | --          if (ctx->m_omx_output_port == (int)nData2)
 | 
	
		
			
				|  |  | --          {
 | 
	
		
			
				|  |  | --            // Got OMX_CommandPortDisable event, alloc new buffers for the output port.
 | 
	
		
			
				|  |  | --            ctx->AllocOMXOutputBuffers();
 | 
	
		
			
				|  |  | --            omx_err = OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortEnable, ctx->m_omx_output_port, NULL);
 | 
	
		
			
				|  |  | --          }
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case OMX_CommandPortEnable:
 | 
	
		
			
				|  |  | --          #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --          CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --            "%s::%s - OMX_CommandPortEnable, nData1(0x%lx), nData2(0x%lx)\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__, nData1, nData2);
 | 
	
		
			
				|  |  | --          #endif
 | 
	
		
			
				|  |  | --          if (ctx->m_omx_output_port == (int)nData2)
 | 
	
		
			
				|  |  | --          {
 | 
	
		
			
				|  |  | --            // Got OMX_CommandPortEnable event.
 | 
	
		
			
				|  |  | --            // OMX_CommandPortDisable will have re-alloced new ones so re-prime
 | 
	
		
			
				|  |  | --            ctx->PrimeFillBuffers();
 | 
	
		
			
				|  |  | --          }
 | 
	
		
			
				|  |  | --          ctx->m_portChanging = false;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --        case OMX_CommandMarkBuffer:
 | 
	
		
			
				|  |  | --          CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --            "%s::%s - OMX_CommandMarkBuffer, nData1(0x%lx), nData2(0x%lx)\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__, nData1, nData2);
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        #endif
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --    case OMX_EventBufferFlag:
 | 
	
		
			
				|  |  | --      if (ctx->m_omx_decoder == hComponent && (nData2 & OMX_BUFFERFLAG_EOS)) {
 | 
	
		
			
				|  |  | --        #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --        if(ctx->m_omx_input_port  == (int)nData1)
 | 
	
		
			
				|  |  | --            CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(input)\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --        #endif
 | 
	
		
			
				|  |  | --        if(ctx->m_omx_output_port == (int)nData1)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --            ctx->m_videoplayback_done = true;
 | 
	
		
			
				|  |  | --            #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --            CLog::Log(LOGDEBUG, "%s::%s - OMX_EventBufferFlag(output)\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --            #endif
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --    case OMX_EventPortSettingsChanged:
 | 
	
		
			
				|  |  | --      #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG,
 | 
	
		
			
				|  |  | --        "%s::%s - OMX_EventPortSettingsChanged(output)\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --      #endif
 | 
	
		
			
				|  |  | --      // not sure nData2 is the input/output ports in this call, docs don't say
 | 
	
		
			
				|  |  | --      if (ctx->m_omx_output_port == (int)nData2)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        // free the current OpenMax output buffers, you must do this before sending
 | 
	
		
			
				|  |  | --        // OMX_CommandPortDisable to component as it expects output buffers
 | 
	
		
			
				|  |  | --        // to be freed before it will issue a OMX_CommandPortDisable event.
 | 
	
		
			
				|  |  | --        ctx->m_portChanging = true;
 | 
	
		
			
				|  |  | --        OMX_SendCommand(ctx->m_omx_decoder, OMX_CommandPortDisable, ctx->m_omx_output_port, NULL);
 | 
	
		
			
				|  |  | --        omx_err = ctx->FreeOMXOutputBuffers(false);
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --    #if defined(OMX_DEBUG_EVENTHANDLER)
 | 
	
		
			
				|  |  | --    case OMX_EventMark:
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "%s::%s - OMX_EventMark\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --    case OMX_EventResourcesAcquired:
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "%s::%s - OMX_EventResourcesAcquired\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --    #endif
 | 
	
		
			
				|  |  | --    case OMX_EventError:
 | 
	
		
			
				|  |  | --      switch((OMX_S32)nData1)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        case OMX_ErrorInsufficientResources:
 | 
	
		
			
				|  |  | --          CLog::Log(LOGERROR, "%s::%s - OMX_EventError, insufficient resources\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --          // we are so frack'ed
 | 
	
		
			
				|  |  | --          //exit(0);
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case OMX_ErrorFormatNotDetected:
 | 
	
		
			
				|  |  | --          CLog::Log(LOGERROR, "%s::%s - OMX_EventError, cannot parse input stream\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case OMX_ErrorPortUnpopulated:
 | 
	
		
			
				|  |  | --          // silently ignore these. We can get them when setting OMX_CommandPortDisable
 | 
	
		
			
				|  |  | --          // on the output port and the component flushes the output buffers.
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        case OMX_ErrorStreamCorrupt:
 | 
	
		
			
				|  |  | --          CLog::Log(LOGERROR, "%s::%s - OMX_EventError, Bitstream corrupt\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --          ctx->m_videoplayback_done = true;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --        default:
 | 
	
		
			
				|  |  | --          CLog::Log(LOGERROR, "%s::%s - OMX_EventError detected, nData1(0x%lx), nData2(0x%lx)\n",
 | 
	
		
			
				|  |  | --            CLASSNAME, __func__, nData1, nData2);
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --      // do this so we don't hang on errors
 | 
	
		
			
				|  |  | --      /*
 | 
	
		
			
				|  |  | --      sem_post(ctx->m_omx_flush_input);
 | 
	
		
			
				|  |  | --      sem_post(ctx->m_omx_flush_output);
 | 
	
		
			
				|  |  | --      */
 | 
	
		
			
				|  |  | --      sem_post(ctx->m_omx_decoder_state_change);
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --    default:
 | 
	
		
			
				|  |  | --      CLog::Log(LOGWARNING,
 | 
	
		
			
				|  |  | --        "%s::%s - Unknown eEvent(0x%x), nData1(0x%lx), nData2(0x%lx)\n",
 | 
	
		
			
				|  |  | --        CLASSNAME, __func__, eEvent, nData1, nData2);
 | 
	
		
			
				|  |  | --    break;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return OMX_ErrorNone;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// StartPlayback -- Kick off video playback.
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::StartDecoder(void)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --  #endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // transition decoder component to IDLE state
 | 
	
		
			
				|  |  | --  omx_err = SetStateForComponent(OMX_StateIdle);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return omx_err;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // transition decoder component to executing state
 | 
	
		
			
				|  |  | --  omx_err = SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s - setting OMX_StateExecuting failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return omx_err;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  //prime the omx output buffers.
 | 
	
		
			
				|  |  | --  PrimeFillBuffers();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return omx_err;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - // StopPlayback -- Stop video playback
 | 
	
		
			
				|  |  | - OMX_ERRORTYPE COpenMaxVideo::StopDecoder(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // transition decoder component from executing to idle
 | 
	
		
			
				|  |  | --  omx_err = SetStateForComponent(OMX_StateIdle);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | -+  if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return omx_err;
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_decoder.SetStateForComponent(OMX_StateIdle);
 | 
	
		
			
				|  |  | -+    if (omx_err)
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - setting OMX_StateIdle failed with omx_err(0x%x)",
 | 
	
		
			
				|  |  | -+        CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // we can free our allocated port buffers in OMX_StateIdle state.
 | 
	
		
			
				|  |  | -   // free OpenMax input buffers.
 | 
	
		
			
				|  |  | --  FreeOMXInputBuffers(true);
 | 
	
		
			
				|  |  | --  // free OpenMax output buffers.
 | 
	
		
			
				|  |  | --  FreeOMXOutputBuffers(true);
 | 
	
		
			
				|  |  | -+  FreeOMXInputBuffers();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_omx_egl_render.IsInitialized())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateIdle);
 | 
	
		
			
				|  |  | -+      if (omx_err)
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s - setting egl OMX_StateIdle failed with omx_err(0x%x)",
 | 
	
		
			
				|  |  | -+          CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      // free OpenMax output buffers.
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_egl_render.DisablePort(m_omx_egl_render.GetOutputPort(), false);
 | 
	
		
			
				|  |  | -+      if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.DisablePort(%d) omx_err(0x%08x)", CLASSNAME, __func__, m_omx_egl_render.GetOutputPort(), omx_err);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // transition decoder component from idle to loaded
 | 
	
		
			
				|  |  | --  omx_err = SetStateForComponent(OMX_StateLoaded);
 | 
	
		
			
				|  |  | --  if (omx_err)
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR,
 | 
	
		
			
				|  |  | --      "%s::%s - setting OMX_StateLoaded failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | --      CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      FreeOMXOutputBuffers();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_egl_render.WaitForCommand(OMX_CommandPortDisable, m_omx_egl_render.GetOutputPort());
 | 
	
		
			
				|  |  | -+      if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s WaitForCommand:OMX_CommandPortDisable omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   return omx_err;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -index e06c41d..9079c13 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -@@ -21,12 +21,35 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(HAVE_LIBOPENMAX)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --#include "OpenMax.h"
 | 
	
		
			
				|  |  | -+#include "system_gl.h"
 | 
	
		
			
				|  |  | - #include <EGL/egl.h>
 | 
	
		
			
				|  |  | - #include <EGL/eglext.h>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#include "linux/OMXCore.h"
 | 
	
		
			
				|  |  | -+#include "linux/OMXClock.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "cores/dvdplayer/DVDStreamInfo.h"
 | 
	
		
			
				|  |  | -+#include "DVDVideoCodec.h"
 | 
	
		
			
				|  |  | -+#include "threads/Event.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include <queue>
 | 
	
		
			
				|  |  | -+#include <semaphore.h>
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+typedef struct omx_demux_packet {
 | 
	
		
			
				|  |  | -+  OMX_U8 *buff;
 | 
	
		
			
				|  |  | -+  int size;
 | 
	
		
			
				|  |  | -+  double dts;
 | 
	
		
			
				|  |  | -+  double pts;
 | 
	
		
			
				|  |  | -+} omx_demux_packet;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+class COpenMaxVideo;
 | 
	
		
			
				|  |  | - // an omx egl video frame
 | 
	
		
			
				|  |  | --typedef struct OpenMaxVideoBuffer {
 | 
	
		
			
				|  |  | -+class COpenMaxVideoBuffer
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+public:
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer(COpenMaxVideo *omv);
 | 
	
		
			
				|  |  | -+  virtual ~COpenMaxVideoBuffer();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   OMX_BUFFERHEADERTYPE *omx_buffer;
 | 
	
		
			
				|  |  | -   int width;
 | 
	
		
			
				|  |  | -   int height;
 | 
	
		
			
				|  |  | -@@ -35,79 +58,86 @@ typedef struct OpenMaxVideoBuffer {
 | 
	
		
			
				|  |  | -   // used for egl based rendering if active
 | 
	
		
			
				|  |  | -   EGLImageKHR egl_image;
 | 
	
		
			
				|  |  | -   GLuint texture_id;
 | 
	
		
			
				|  |  | --} OpenMaxVideoBuffer;
 | 
	
		
			
				|  |  | -+  // reference counting
 | 
	
		
			
				|  |  | -+  COpenMaxVideoBuffer* Acquire();
 | 
	
		
			
				|  |  | -+  long                 Release();
 | 
	
		
			
				|  |  | -+  void                 Sync();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  COpenMaxVideo *m_omv;
 | 
	
		
			
				|  |  | -+  long m_refs;
 | 
	
		
			
				|  |  | -+private:
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --class COpenMaxVideo : public COpenMax
 | 
	
		
			
				|  |  | -+class COpenMaxVideo
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -   COpenMaxVideo();
 | 
	
		
			
				|  |  | -   virtual ~COpenMaxVideo();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Required overrides
 | 
	
		
			
				|  |  | --  bool Open(CDVDStreamInfo &hints);
 | 
	
		
			
				|  |  | --  void Close(void);
 | 
	
		
			
				|  |  | --  int  Decode(uint8_t *pData, int iSize, double dts, double pts);
 | 
	
		
			
				|  |  | --  void Reset(void);
 | 
	
		
			
				|  |  | --  bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
 | 
	
		
			
				|  |  | --  void SetDropState(bool bDrop);
 | 
	
		
			
				|  |  | -+  virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
 | 
	
		
			
				|  |  | -+  virtual void Dispose(void);
 | 
	
		
			
				|  |  | -+  virtual int  Decode(uint8_t *pData, int iSize, double dts, double pts);
 | 
	
		
			
				|  |  | -+  virtual void Reset(void);
 | 
	
		
			
				|  |  | -+  virtual bool GetPicture(DVDVideoPicture *pDvdVideoPicture);
 | 
	
		
			
				|  |  | -+  virtual bool ClearPicture(DVDVideoPicture* pDvdVideoPicture);
 | 
	
		
			
				|  |  | -+  virtual unsigned GetAllowedReferences() { return 2; }
 | 
	
		
			
				|  |  | -+  virtual void SetDropState(bool bDrop);
 | 
	
		
			
				|  |  | -+  virtual const char* GetName(void) { return (const char*)m_pFormatName; }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // OpenMax decoder callback routines.
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer);
 | 
	
		
			
				|  |  | -+  void ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   void QueryCodec(void);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE PrimeFillBuffers(void);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE AllocOMXInputBuffers(void);
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE FreeOMXInputBuffers(bool wait);
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE AllocOMXOutputBuffers(void);
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE FreeOMXOutputBuffers(bool wait);
 | 
	
		
			
				|  |  | --  static void CallbackAllocOMXEGLTextures(void*);
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE FreeOMXInputBuffers(void);
 | 
	
		
			
				|  |  | -+  bool AllocOMXOutputBuffers(void);
 | 
	
		
			
				|  |  | -+  bool FreeOMXOutputBuffers(void);
 | 
	
		
			
				|  |  | -+  static bool CallbackAllocOMXEGLTextures(void*);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE AllocOMXOutputEGLTextures(void);
 | 
	
		
			
				|  |  | --  static void CallbackFreeOMXEGLTextures(void*);
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE FreeOMXOutputEGLTextures(bool wait);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // TODO Those should move into the base class. After start actions can be executed by callbacks.
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE StartDecoder(void);
 | 
	
		
			
				|  |  | -+  static bool CallbackFreeOMXEGLTextures(void*);
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE FreeOMXOutputEGLTextures(void);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE StopDecoder(void);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // OpenMax decoder callback routines.
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE DecoderEventHandler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData,
 | 
	
		
			
				|  |  | --    OMX_EVENTTYPE eEvent, OMX_U32 nData1, OMX_U32 nData2, OMX_PTR pEventData);
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE DecoderEmptyBufferDone(
 | 
	
		
			
				|  |  | --    OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBuffer);
 | 
	
		
			
				|  |  | --  virtual OMX_ERRORTYPE DecoderFillBufferDone(
 | 
	
		
			
				|  |  | --    OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_BUFFERHEADERTYPE* pBufferHeader);
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // EGL Resources
 | 
	
		
			
				|  |  | -   EGLDisplay        m_egl_display;
 | 
	
		
			
				|  |  | -   EGLContext        m_egl_context;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Video format
 | 
	
		
			
				|  |  | --  DVDVideoPicture   m_videobuffer;
 | 
	
		
			
				|  |  | -   bool              m_drop_state;
 | 
	
		
			
				|  |  | -   int               m_decoded_width;
 | 
	
		
			
				|  |  | -   int               m_decoded_height;
 | 
	
		
			
				|  |  | -+  unsigned int      m_egl_buffer_count;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  bool m_port_settings_changed;
 | 
	
		
			
				|  |  | -+  const char        *m_pFormatName;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   std::queue<double> m_dts_queue;
 | 
	
		
			
				|  |  | -   std::queue<omx_demux_packet> m_demux_queue;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // OpenMax input buffers (demuxer packets)
 | 
	
		
			
				|  |  | --  pthread_mutex_t   m_omx_input_mutex;
 | 
	
		
			
				|  |  | --  std::queue<OMX_BUFFERHEADERTYPE*> m_omx_input_avaliable;
 | 
	
		
			
				|  |  | --  std::vector<OMX_BUFFERHEADERTYPE*> m_omx_input_buffers;
 | 
	
		
			
				|  |  | --  bool              m_omx_input_eos;
 | 
	
		
			
				|  |  | --  int               m_omx_input_port;
 | 
	
		
			
				|  |  | --  //sem_t             *m_omx_flush_input;
 | 
	
		
			
				|  |  | --  CEvent            m_input_consumed_event;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   // OpenMax output buffers (video frames)
 | 
	
		
			
				|  |  | -   pthread_mutex_t   m_omx_output_mutex;
 | 
	
		
			
				|  |  | --  std::queue<OpenMaxVideoBuffer*> m_omx_output_busy;
 | 
	
		
			
				|  |  | --  std::queue<OpenMaxVideoBuffer*> m_omx_output_ready;
 | 
	
		
			
				|  |  | --  std::vector<OpenMaxVideoBuffer*> m_omx_output_buffers;
 | 
	
		
			
				|  |  | --  bool              m_omx_output_eos;
 | 
	
		
			
				|  |  | --  int               m_omx_output_port;
 | 
	
		
			
				|  |  | --  //sem_t             *m_omx_flush_output;
 | 
	
		
			
				|  |  | -+  std::vector<COpenMaxVideoBuffer*> m_omx_output_busy;
 | 
	
		
			
				|  |  | -+  std::queue<COpenMaxVideoBuffer*> m_omx_output_ready;
 | 
	
		
			
				|  |  | -+  std::vector<COpenMaxVideoBuffer*> m_omx_output_buffers;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // initialize OpenMax and get decoder component
 | 
	
		
			
				|  |  | -+  bool Initialize( const CStdString &decoder_name);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // Components
 | 
	
		
			
				|  |  | -+  COMXCoreComponent m_omx_decoder;
 | 
	
		
			
				|  |  | -+  COMXCoreComponent m_omx_egl_render;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  bool              m_portChanging;
 | 
	
		
			
				|  |  | -+  COMXCoreTunel     m_omx_tunnel;
 | 
	
		
			
				|  |  | -+  OMX_VIDEO_CODINGTYPE m_codingType;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  volatile bool     m_videoplayback_done;
 | 
	
		
			
				|  |  | -+  bool PortSettingsChanged();
 | 
	
		
			
				|  |  | -+  bool SendDecoderConfig(uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | -+  bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - // defined(HAVE_LIBOPENMAX)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
 | 
	
		
			
				|  |  | -index a485275..d607f55 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
 | 
	
		
			
				|  |  | -@@ -2988,7 +2988,9 @@ bool CDVDPlayer::OpenVideoStream(int iStream, int source, bool reset)
 | 
	
		
			
				|  |  | -       hint.aspect = aspect;
 | 
	
		
			
				|  |  | -       hint.forced_aspect = true;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+#ifndef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -     hint.software = true;
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   boost::shared_ptr<CPVRClient> client;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index 99b3155..fddb7f7 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -325,6 +325,9 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   while (!m_bStop)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -+    DemuxPacket staticPacket = {};
 | 
	
		
			
				|  |  | -+    DemuxPacket* pPacket = NULL;
 | 
	
		
			
				|  |  | -+    bool bPacketDrop = false;
 | 
	
		
			
				|  |  | -     int iQueueTimeOut = (int)(m_stalled ? frametime / 4 : frametime * 10) / 1000;
 | 
	
		
			
				|  |  | -     int iPriority = (m_speed == DVD_PLAYSPEED_PAUSE && m_started) ? 1 : 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -361,8 +364,10 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | -         OutputPicture(&picture, pts);
 | 
	
		
			
				|  |  | -         pts+= frametime;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      continue;
 | 
	
		
			
				|  |  | -+      pPacket = &staticPacket;
 | 
	
		
			
				|  |  | -+      bPacketDrop = false;
 | 
	
		
			
				|  |  | -+      goto submit_empty_packet;
 | 
	
		
			
				|  |  | -+      //continue;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (pMsg->IsType(CDVDMsg::GENERAL_SYNCHRONIZE))
 | 
	
		
			
				|  |  | -@@ -489,9 +494,12 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      DemuxPacket* pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
 | 
	
		
			
				|  |  | --      bool bPacketDrop     = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+      pPacket = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacket();
 | 
	
		
			
				|  |  | -+      bPacketDrop     = ((CDVDMsgDemuxerPacket*)pMsg)->GetPacketDrop();
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+submit_empty_packet:
 | 
	
		
			
				|  |  | -+    if (ret == MSGQ_TIMEOUT || pMsg->IsType(CDVDMsg::DEMUXER_PACKET))
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -       if (m_stalled)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -         CLog::Log(LOGINFO, "CDVDPlayerVideo - Stillframe left, switching to normal playback");
 | 
	
		
			
				|  |  | -@@ -749,7 +757,8 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     // all data is used by the decoder, we can safely free it now
 | 
	
		
			
				|  |  | --    pMsg->Release();
 | 
	
		
			
				|  |  | -+    if (ret != MSGQ_TIMEOUT)
 | 
	
		
			
				|  |  | -+        pMsg->Release();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // we need to let decoder release any picture retained resources.
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/OMXCore.cpp b/xbmc/linux/OMXCore.cpp
 | 
	
		
			
				|  |  | -index 6e7d9a9..99e407a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/OMXCore.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/OMXCore.cpp
 | 
	
		
			
				|  |  | -@@ -460,7 +460,12 @@ void COMXCoreComponent::FlushInput()
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "COMXCoreComponent::FlushInput - Error on component %s omx_err(0x%08x)", 
 | 
	
		
			
				|  |  | -               m_componentName.c_str(), (int)omx_err);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  WaitForCommand(OMX_CommandFlush, m_input_port);
 | 
	
		
			
				|  |  | -+  omx_err = WaitForCommand(OMX_CommandFlush, m_input_port);
 | 
	
		
			
				|  |  | -+  if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "COMXCoreComponent::FlushInput - %s WaitForCommand omx_err(0x%08x)",
 | 
	
		
			
				|  |  | -+              m_componentName.c_str(), (int)omx_err);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COMXCoreComponent::FlushOutput()
 | 
	
		
			
				|  |  | -@@ -477,7 +482,12 @@ void COMXCoreComponent::FlushOutput()
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "COMXCoreComponent::FlushOutput - Error on component %s omx_err(0x%08x)", 
 | 
	
		
			
				|  |  | -               m_componentName.c_str(), (int)omx_err);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  WaitForCommand(OMX_CommandFlush, m_output_port);
 | 
	
		
			
				|  |  | -+  omx_err = WaitForCommand(OMX_CommandFlush, m_output_port);
 | 
	
		
			
				|  |  | -+  if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "COMXCoreComponent::FlushOutput - %s WaitForCommand omx_err(0x%08x)",
 | 
	
		
			
				|  |  | -+              m_componentName.c_str(), (int)omx_err);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - // timeout in milliseconds
 | 
	
		
			
				|  |  | -@@ -1149,7 +1159,12 @@ OMX_STATETYPE COMXCoreComponent::GetState()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   OMX_STATETYPE state;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  OMX_GetState(m_handle, &state);
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err = OMX_GetState(m_handle, &state);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "COMXCoreComponent::GetState - %s failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | -+      m_componentName.c_str(), omx_err);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   return state;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -1307,6 +1322,8 @@ OMX_ERRORTYPE COMXCoreComponent::DisablePort(unsigned int port, bool wait)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - OMX_ERRORTYPE COMXCoreComponent::UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+if (m_callbacks.FillBufferDone == &COMXCoreComponent::DecoderFillBufferDoneCallback)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(!m_handle)
 | 
	
		
			
				|  |  | -@@ -1383,8 +1400,21 @@ OMX_ERRORTYPE COMXCoreComponent::UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr,
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   return omx_err;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -+else
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | -+    omx_err = OMX_UseEGLImage(m_handle, ppBufferHdr, nPortIndex, pAppPrivate, eglImage);
 | 
	
		
			
				|  |  | -+    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - %s failed with omx_err(0x%x)\n",
 | 
	
		
			
				|  |  | -+                CLASSNAME, __func__, m_componentName.c_str(), omx_err);
 | 
	
		
			
				|  |  | -+      return omx_err;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  return omx_err;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEXTYPE index)
 | 
	
		
			
				|  |  | -+bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEXTYPE index, OMX_CALLBACKTYPE *callbacks)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -1419,6 +1449,13 @@ bool COMXCoreComponent::Initialize( const std::string &component_name, OMX_INDEX
 | 
	
		
			
				|  |  | -   m_callbacks.EmptyBufferDone = &COMXCoreComponent::DecoderEmptyBufferDoneCallback;
 | 
	
		
			
				|  |  | -   m_callbacks.FillBufferDone  = &COMXCoreComponent::DecoderFillBufferDoneCallback;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  if (callbacks && callbacks->EventHandler)
 | 
	
		
			
				|  |  | -+    m_callbacks.EventHandler    = callbacks->EventHandler;
 | 
	
		
			
				|  |  | -+  if (callbacks && callbacks->EmptyBufferDone)
 | 
	
		
			
				|  |  | -+    m_callbacks.EmptyBufferDone = callbacks->EmptyBufferDone;
 | 
	
		
			
				|  |  | -+  if (callbacks && callbacks->FillBufferDone)
 | 
	
		
			
				|  |  | -+    m_callbacks.FillBufferDone  = callbacks->FillBufferDone;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // Get video component handle setting up callbacks, component is in loaded state on return.
 | 
	
		
			
				|  |  | -   if(!m_handle)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/OMXCore.h b/xbmc/linux/OMXCore.h
 | 
	
		
			
				|  |  | -index 54d35aa..5b9c2f9 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/OMXCore.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/OMXCore.h
 | 
	
		
			
				|  |  | -@@ -109,7 +109,7 @@ class COMXCoreComponent
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE DisablePort(unsigned int port, bool wait = true);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE UseEGLImage(OMX_BUFFERHEADERTYPE** ppBufferHdr, OMX_U32 nPortIndex, OMX_PTR pAppPrivate, void* eglImage);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  bool          Initialize( const std::string &component_name, OMX_INDEXTYPE index);
 | 
	
		
			
				|  |  | -+  bool          Initialize( const std::string &component_name, OMX_INDEXTYPE index, OMX_CALLBACKTYPE *callbacks = NULL);
 | 
	
		
			
				|  |  | -   bool          IsInitialized();
 | 
	
		
			
				|  |  | -   bool          Deinitialize();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From e9b71fb1ee80896444d3301f919bf315a96530a3 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 3 May 2014 11:57:25 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 43/94] [omxcodec] Enable for dvd menus
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp | 4 ++++
 | 
	
		
			
				|  |  | - 1 file changed, 4 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
 | 
	
		
			
				|  |  | -index 18b8e3a..c85c8d2 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/DVDFactoryCodec.cpp
 | 
	
		
			
				|  |  | -@@ -194,6 +194,10 @@ CDVDVideoCodec* CDVDFactoryCodec::CreateVideoCodec(CDVDStreamInfo &hint, unsigne
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "CDVDFactoryCodec: compiled in hardware support: %s", hwSupport.c_str());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if defined(HAVE_LIBOPENMAX)
 | 
	
		
			
				|  |  | -+  // libopenmax can handle dvd playback including stills
 | 
	
		
			
				|  |  | -+  if (!CSettings::Get().GetBool("videoplayer.useomx"))
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   if (hint.stills && (hint.codec == AV_CODEC_ID_MPEG2VIDEO || hint.codec == AV_CODEC_ID_MPEG1VIDEO))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -      // If dvd is an mpeg2 and hint.stills
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From a7a4ccc26d85d1362a77b718564ddb1f08ca1246 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 3 Feb 2014 22:27:44 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 44/94] [omxcodec] Add omx specific texture
 | 
	
		
			
				|  |  | - create/upload/delete functions
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 33 +++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/LinuxRendererGLES.h   |  4 +++
 | 
	
		
			
				|  |  | - 2 files changed, 37 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -index 6d879e3..279aa90 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -@@ -805,6 +805,12 @@ void CLinuxRendererGLES::LoadShaders(int field)
 | 
	
		
			
				|  |  | -     m_textureCreate = &CLinuxRendererGLES::CreateNV12Texture;
 | 
	
		
			
				|  |  | -     m_textureDelete = &CLinuxRendererGLES::DeleteNV12Texture;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  else if (m_format == RENDER_FMT_OMXEGL)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_textureUpload = &CLinuxRendererGLES::UploadOMXEGLTexture;
 | 
	
		
			
				|  |  | -+    m_textureCreate = &CLinuxRendererGLES::CreateOMXEGLTexture;
 | 
	
		
			
				|  |  | -+    m_textureDelete = &CLinuxRendererGLES::DeleteOMXEGLTexture;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     // default to YV12 texture handlers
 | 
	
		
			
				|  |  | -@@ -2487,6 +2493,33 @@ bool CLinuxRendererGLES::CreateSurfaceTexture(int index)
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+//********************************************************************************************************
 | 
	
		
			
				|  |  | -+// SurfaceTexture creation, deletion, copying + clearing
 | 
	
		
			
				|  |  | -+//********************************************************************************************************
 | 
	
		
			
				|  |  | -+void CLinuxRendererGLES::UploadOMXEGLTexture(int index)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+#ifdef HAVE_LIBOPENMAX
 | 
	
		
			
				|  |  | -+  YUVBUFFER &buf = m_buffers[index];
 | 
	
		
			
				|  |  | -+  if (buf.openMaxBuffer)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    //buf.openMaxBuffer->Sync();
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+void CLinuxRendererGLES::DeleteOMXEGLTexture(int index)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+#ifdef HAVE_LIBOPENMAX
 | 
	
		
			
				|  |  | -+  YUVBUFFER &buf = m_buffers[index];
 | 
	
		
			
				|  |  | -+  if (buf.openMaxBuffer)
 | 
	
		
			
				|  |  | -+    SAFE_RELEASE(buf.openMaxBuffer);
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+bool CLinuxRendererGLES::CreateOMXEGLTexture(int index)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  DeleteOMXEGLTexture(index);
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - void CLinuxRendererGLES::SetTextureFilter(GLenum method)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   for (int i = 0 ; i<m_NumYV12Buffers ; i++)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
 | 
	
		
			
				|  |  | -index 0ca56a2..f3dd3d3 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.h
 | 
	
		
			
				|  |  | -@@ -212,6 +212,10 @@ class CLinuxRendererGLES : public CBaseRenderer
 | 
	
		
			
				|  |  | -   void DeleteSurfaceTexture(int index);
 | 
	
		
			
				|  |  | -   bool CreateSurfaceTexture(int index);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  void UploadOMXEGLTexture(int index);
 | 
	
		
			
				|  |  | -+  void DeleteOMXEGLTexture(int index);
 | 
	
		
			
				|  |  | -+  bool CreateOMXEGLTexture(int index);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   void CalculateTextureSourceRects(int source, int num_planes);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // renderers
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 6a8bd5509ada85a05ad4672a33b76418573382ea Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 3 Feb 2014 22:50:43 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 45/94] [omxcodec] Add shared pointer to delay shutdown of
 | 
	
		
			
				|  |  | - codec until buffers are returned
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp        | 13 +++----------
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecOpenMax.h          |  3 ++-
 | 
	
		
			
				|  |  | - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp      | 21 ++++++++++++++++++++-
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h |  5 ++++-
 | 
	
		
			
				|  |  | - 4 files changed, 29 insertions(+), 13 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -index 7d33192..ef10555 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -@@ -28,7 +28,6 @@
 | 
	
		
			
				|  |  | - #include "DVDClock.h"
 | 
	
		
			
				|  |  | - #include "DVDStreamInfo.h"
 | 
	
		
			
				|  |  | - #include "DVDVideoCodecOpenMax.h"
 | 
	
		
			
				|  |  | --#include "OpenMaxVideo.h"
 | 
	
		
			
				|  |  | - #include "settings/Settings.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -36,8 +35,8 @@
 | 
	
		
			
				|  |  | - ////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | - ////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | - CDVDVideoCodecOpenMax::CDVDVideoCodecOpenMax()
 | 
	
		
			
				|  |  | -+ : m_omx_decoder( new COpenMaxVideo )
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  m_omx_decoder = NULL;
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "%s::%s %p\n", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -49,8 +48,7 @@ CDVDVideoCodecOpenMax::~CDVDVideoCodecOpenMax()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool CDVDVideoCodecOpenMax::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  m_omx_decoder = new COpenMaxVideo;
 | 
	
		
			
				|  |  | --  return m_omx_decoder->Open(hints, options);
 | 
	
		
			
				|  |  | -+  return m_omx_decoder->Open(hints, options, m_omx_decoder);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - const char* CDVDVideoCodecOpenMax::GetName(void)
 | 
	
		
			
				|  |  | -@@ -60,12 +58,7 @@ const char* CDVDVideoCodecOpenMax::GetName(void)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CDVDVideoCodecOpenMax::Dispose()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if (m_omx_decoder)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_omx_decoder->Dispose();
 | 
	
		
			
				|  |  | --    delete m_omx_decoder;
 | 
	
		
			
				|  |  | --    m_omx_decoder = NULL;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+  m_omx_decoder->Dispose();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CDVDVideoCodecOpenMax::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -index 67cc235..b7c0c1b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -@@ -22,6 +22,7 @@
 | 
	
		
			
				|  |  | - #if defined(HAVE_LIBOPENMAX)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "DVDVideoCodec.h"
 | 
	
		
			
				|  |  | -+#include "OpenMaxVideo.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - class COpenMaxVideo;
 | 
	
		
			
				|  |  | - class CDVDVideoCodecOpenMax : public CDVDVideoCodec
 | 
	
		
			
				|  |  | -@@ -42,7 +43,7 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec
 | 
	
		
			
				|  |  | -   virtual const char* GetName(void);
 | 
	
		
			
				|  |  | -   
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | --  COpenMaxVideo     *m_omx_decoder;
 | 
	
		
			
				|  |  | -+  OpenMaxVideoPtr m_omx_decoder;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index aca2e0d..29b5bb9 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -126,6 +126,7 @@ COpenMaxVideo::COpenMaxVideo()
 | 
	
		
			
				|  |  | -   m_egl_buffer_count = 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_port_settings_changed = false;
 | 
	
		
			
				|  |  | -+  m_finished = false;
 | 
	
		
			
				|  |  | -   m_pFormatName = "omx-xxxx";
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -134,6 +135,7 @@ COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | -+  assert(m_finished);
 | 
	
		
			
				|  |  | -   if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     if (m_omx_tunnel.IsInitialized())
 | 
	
		
			
				|  |  | -@@ -149,7 +151,7 @@ COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | -   pthread_mutex_destroy(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -@@ -161,6 +163,7 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_myself = myself;
 | 
	
		
			
				|  |  | -   m_decoded_width  = hints.width;
 | 
	
		
			
				|  |  | -   m_decoded_height = hints.height;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -331,6 +334,15 @@ void COpenMaxVideo::Dispose()
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | -+  // we are happy to exit, but let last shared pointer being deleted trigger the destructor
 | 
	
		
			
				|  |  | -+  bool done = false;
 | 
	
		
			
				|  |  | -+  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  if (m_omx_output_busy.empty())
 | 
	
		
			
				|  |  | -+    done = true;
 | 
	
		
			
				|  |  | -+  m_finished = true;
 | 
	
		
			
				|  |  | -+  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  if (done)
 | 
	
		
			
				|  |  | -+    m_myself.reset();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COpenMaxVideo::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | -@@ -752,6 +764,13 @@ void COpenMaxVideo::ReleaseOpenMaxBuffer(COpenMaxVideoBuffer *buffer)
 | 
	
		
			
				|  |  | -   m_omx_output_busy.erase(std::remove(m_omx_output_busy.begin(), m_omx_output_busy.end(), buffer), m_omx_output_busy.end());
 | 
	
		
			
				|  |  | -   pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -   ReturnOpenMaxBuffer(buffer);
 | 
	
		
			
				|  |  | -+  bool done = false;
 | 
	
		
			
				|  |  | -+  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  if (m_finished && m_omx_output_busy.empty())
 | 
	
		
			
				|  |  | -+    done = true;
 | 
	
		
			
				|  |  | -+  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  if (done)
 | 
	
		
			
				|  |  | -+    m_myself.reset();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -index 9079c13..0975e8a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -@@ -43,6 +43,7 @@ typedef struct omx_demux_packet {
 | 
	
		
			
				|  |  | - } omx_demux_packet;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - class COpenMaxVideo;
 | 
	
		
			
				|  |  | -+typedef boost::shared_ptr<COpenMaxVideo> OpenMaxVideoPtr;
 | 
	
		
			
				|  |  | - // an omx egl video frame
 | 
	
		
			
				|  |  | - class COpenMaxVideoBuffer
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -@@ -75,7 +76,7 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | -   virtual ~COpenMaxVideo();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Required overrides
 | 
	
		
			
				|  |  | --  virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options);
 | 
	
		
			
				|  |  | -+  virtual bool Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself);
 | 
	
		
			
				|  |  | -   virtual void Dispose(void);
 | 
	
		
			
				|  |  | -   virtual int  Decode(uint8_t *pData, int iSize, double dts, double pts);
 | 
	
		
			
				|  |  | -   virtual void Reset(void);
 | 
	
		
			
				|  |  | -@@ -112,9 +113,11 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | -   int               m_decoded_width;
 | 
	
		
			
				|  |  | -   int               m_decoded_height;
 | 
	
		
			
				|  |  | -   unsigned int      m_egl_buffer_count;
 | 
	
		
			
				|  |  | -+  bool              m_finished;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool m_port_settings_changed;
 | 
	
		
			
				|  |  | -   const char        *m_pFormatName;
 | 
	
		
			
				|  |  | -+  OpenMaxVideoPtr   m_myself;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   std::queue<double> m_dts_queue;
 | 
	
		
			
				|  |  | -   std::queue<omx_demux_packet> m_demux_queue;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From e8f40e625203fe4113e2687d3730c38770cc0857 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 3 Feb 2014 23:11:31 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 46/94] [omxcodec] Fix for aspect ratio in non-square pixel
 | 
	
		
			
				|  |  | - modes
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 17 +++++++++++++++++
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h   |  3 +++
 | 
	
		
			
				|  |  | - 2 files changed, 20 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index 29b5bb9..7e23c87 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -63,6 +63,7 @@ COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
 | 
	
		
			
				|  |  | -   index = 0;
 | 
	
		
			
				|  |  | -   egl_image = 0;
 | 
	
		
			
				|  |  | -   texture_id = 0;
 | 
	
		
			
				|  |  | -+  m_aspect_ratio = 0.0f;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - COpenMaxVideoBuffer::~COpenMaxVideoBuffer()
 | 
	
		
			
				|  |  | -@@ -166,6 +167,8 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
 | 
	
		
			
				|  |  | -   m_myself = myself;
 | 
	
		
			
				|  |  | -   m_decoded_width  = hints.width;
 | 
	
		
			
				|  |  | -   m_decoded_height = hints.height;
 | 
	
		
			
				|  |  | -+  m_forced_aspect_ratio = hints.forced_aspect;
 | 
	
		
			
				|  |  | -+  m_aspect_ratio = hints.aspect;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_egl_display = g_Windowing.GetEGLDisplay();
 | 
	
		
			
				|  |  | -   m_egl_context = g_Windowing.GetEGLContext();
 | 
	
		
			
				|  |  | -@@ -435,6 +438,9 @@ bool COpenMaxVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  if (!m_forced_aspect_ratio && pixel_aspect.nX && pixel_aspect.nY)
 | 
	
		
			
				|  |  | -+    m_aspect_ratio = (float)pixel_aspect.nX * port_def.format.video.nFrameWidth /
 | 
	
		
			
				|  |  | -+      ((float)pixel_aspect.nY * port_def.format.video.nFrameHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (m_port_settings_changed)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -800,6 +806,16 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->iDisplayWidth  = m_decoded_width;
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->iDisplayHeight = m_decoded_height;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    if (buffer->m_aspect_ratio > 0.0 && !m_forced_aspect_ratio)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      pDvdVideoPicture->iDisplayWidth  = ((int)lrint(pDvdVideoPicture->iHeight * buffer->m_aspect_ratio)) & -3;
 | 
	
		
			
				|  |  | -+      if (pDvdVideoPicture->iDisplayWidth > pDvdVideoPicture->iWidth)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        pDvdVideoPicture->iDisplayWidth  = pDvdVideoPicture->iWidth;
 | 
	
		
			
				|  |  | -+        pDvdVideoPicture->iDisplayHeight = ((int)lrint(pDvdVideoPicture->iWidth / buffer->m_aspect_ratio)) & -3;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -     if (!m_dts_queue.empty())
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -@@ -853,6 +869,7 @@ OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // queue output omx buffer to ready list.
 | 
	
		
			
				|  |  | -   pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  buffer->m_aspect_ratio = m_aspect_ratio;
 | 
	
		
			
				|  |  | -   m_omx_output_ready.push(buffer);
 | 
	
		
			
				|  |  | -   pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -index 0975e8a..9138a20 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -@@ -54,6 +54,7 @@ class COpenMaxVideoBuffer
 | 
	
		
			
				|  |  | -   OMX_BUFFERHEADERTYPE *omx_buffer;
 | 
	
		
			
				|  |  | -   int width;
 | 
	
		
			
				|  |  | -   int height;
 | 
	
		
			
				|  |  | -+  float m_aspect_ratio;
 | 
	
		
			
				|  |  | -   int index;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // used for egl based rendering if active
 | 
	
		
			
				|  |  | -@@ -114,6 +115,8 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | -   int               m_decoded_height;
 | 
	
		
			
				|  |  | -   unsigned int      m_egl_buffer_count;
 | 
	
		
			
				|  |  | -   bool              m_finished;
 | 
	
		
			
				|  |  | -+  float             m_aspect_ratio;
 | 
	
		
			
				|  |  | -+  bool              m_forced_aspect_ratio;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool m_port_settings_changed;
 | 
	
		
			
				|  |  | -   const char        *m_pFormatName;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From e42ca92b464ad88dbe0f8b0d86080d64d52e08a8 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 3 Feb 2014 23:19:22 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 47/94] [omxcodec] Report error when codec not enabled
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 10 +++++++++-
 | 
	
		
			
				|  |  | - 1 file changed, 9 insertions(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index 7e23c87..2ae722b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -43,6 +43,7 @@
 | 
	
		
			
				|  |  | - #include <IL/OMX_Image.h>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "cores/omxplayer/OMXImage.h"
 | 
	
		
			
				|  |  | -+#include "linux/RBP.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define DTS_QUEUE
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -155,7 +156,7 @@ COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | - bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenMaxVideoPtr myself)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s useomx:%d software:%d", CLASSNAME, __func__, CSettings::Get().GetBool("videoplayer.useomx"), hints.software);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // we always qualify even if DVDFactoryCodec does this too.
 | 
	
		
			
				|  |  | -@@ -232,6 +233,13 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
 | 
	
		
			
				|  |  | -     break;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  if ( (m_codingType == OMX_VIDEO_CodingMPEG2 && !g_RBP.GetCodecMpg2() ) ||
 | 
	
		
			
				|  |  | -+       (m_codingType == OMX_VIDEO_CodingWMV   && !g_RBP.GetCodecWvc1() ) )
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGWARNING, "%s::%s Codec %s is not supported\n", CLASSNAME, __func__, m_pFormatName);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // initialize OpenMAX.
 | 
	
		
			
				|  |  | -   if (!m_omx_decoder.Initialize("OMX.broadcom.video_decode", OMX_IndexParamVideoInit))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 55b0b157ba32d03ca0ec854b7935aee5601810d8 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Tue, 4 Feb 2014 17:29:37 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 48/94] [omxcodec] Add deinterlace support
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp    |   2 +-
 | 
	
		
			
				|  |  | - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp     | 106 ++++++++++++++++++---
 | 
	
		
			
				|  |  | - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h |   9 +-
 | 
	
		
			
				|  |  | - 3 files changed, 103 insertions(+), 14 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -index 279aa90..a57abe4 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -@@ -2607,7 +2607,7 @@ bool CLinuxRendererGLES::Supports(EDEINTERLACEMODE mode)
 | 
	
		
			
				|  |  | -     return true;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(m_renderMethod & RENDER_OMXEGL)
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | -+    return true;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(m_renderMethod & RENDER_EGLIMG)
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index 2ae722b..fbf1458 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -33,6 +33,7 @@
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - #include "utils/TimeUtils.h"
 | 
	
		
			
				|  |  | - #include "settings/Settings.h"
 | 
	
		
			
				|  |  | -+#include "settings/MediaSettings.h"
 | 
	
		
			
				|  |  | - #include "ApplicationMessenger.h"
 | 
	
		
			
				|  |  | - #include "Application.h"
 | 
	
		
			
				|  |  | - #include "threads/Atomics.h"
 | 
	
		
			
				|  |  | -@@ -130,6 +131,10 @@ COpenMaxVideo::COpenMaxVideo()
 | 
	
		
			
				|  |  | -   m_port_settings_changed = false;
 | 
	
		
			
				|  |  | -   m_finished = false;
 | 
	
		
			
				|  |  | -   m_pFormatName = "omx-xxxx";
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_deinterlace = false;
 | 
	
		
			
				|  |  | -+  m_deinterlace_request = VS_DEINTERLACEMODE_OFF;
 | 
	
		
			
				|  |  | -+  m_deinterlace_second_field = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | -@@ -140,13 +145,17 @@ COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | -   assert(m_finished);
 | 
	
		
			
				|  |  | -   if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if (m_omx_tunnel.IsInitialized())
 | 
	
		
			
				|  |  | --      m_omx_tunnel.Deestablish();
 | 
	
		
			
				|  |  | -+    if (m_omx_tunnel_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -+      m_omx_tunnel_decoder.Deestablish();
 | 
	
		
			
				|  |  | -+    if (m_omx_tunnel_image_fx.IsInitialized())
 | 
	
		
			
				|  |  | -+      m_omx_tunnel_image_fx.Deestablish();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     StopDecoder();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (m_omx_egl_render.IsInitialized())
 | 
	
		
			
				|  |  | -       m_omx_egl_render.Deinitialize();
 | 
	
		
			
				|  |  | -+    if (m_omx_image_fx.IsInitialized())
 | 
	
		
			
				|  |  | -+      m_omx_image_fx.Deinitialize();
 | 
	
		
			
				|  |  | -     if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -       m_omx_decoder.Deinitialize();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -@@ -165,6 +174,8 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_deinterlace_request = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   m_myself = myself;
 | 
	
		
			
				|  |  | -   m_decoded_width  = hints.width;
 | 
	
		
			
				|  |  | -   m_decoded_height = hints.height;
 | 
	
		
			
				|  |  | -@@ -467,6 +478,49 @@ bool COpenMaxVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  OMX_CONFIG_INTERLACETYPE interlace;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(interlace);
 | 
	
		
			
				|  |  | -+  interlace.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_deinterlace_request == VS_DEINTERLACEMODE_FORCE)
 | 
	
		
			
				|  |  | -+    m_deinterlace = true;
 | 
	
		
			
				|  |  | -+  else if (m_deinterlace_request == VS_DEINTERLACEMODE_OFF)
 | 
	
		
			
				|  |  | -+    m_deinterlace = false;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d",
 | 
	
		
			
				|  |  | -+  CLASSNAME, __func__, port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight, port_def.format.video.xFramerate / (float) (1 << 16),
 | 
	
		
			
				|  |  | -+      interlace.eMode, m_deinterlace);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_deinterlace)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (!m_omx_image_fx.Initialize("OMX.broadcom.image_fx", OMX_IndexParamImageInit))
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s error m_omx_image_fx.Initialize", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_deinterlace)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    OMX_CONFIG_IMAGEFILTERPARAMSTYPE image_filter;
 | 
	
		
			
				|  |  | -+    OMX_INIT_STRUCTURE(image_filter);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    image_filter.nPortIndex = m_omx_image_fx.GetOutputPort();
 | 
	
		
			
				|  |  | -+    image_filter.nNumParams = 1;
 | 
	
		
			
				|  |  | -+    image_filter.nParams[0] = 3;
 | 
	
		
			
				|  |  | -+    image_filter.eImageFilter = OMX_ImageFilterDeInterlaceAdvanced;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_image_fx.SetConfig(OMX_IndexConfigCommonImageFilterParameters, &image_filter);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - OMX_IndexConfigCommonImageFilterParameters omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   OMX_CALLBACKTYPE callbacks = { NULL, NULL, DecoderFillBufferDoneCallback };
 | 
	
		
			
				|  |  | -   if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit, &callbacks))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -487,19 +541,40 @@ bool COpenMaxVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_omx_egl_render.ResetEos();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | --      port_def.format.video.nFrameWidth, port_def.format.video.nFrameHeight,
 | 
	
		
			
				|  |  | --      port_def.format.video.xFramerate / (float)(1<<16), 0,0);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_omx_tunnel.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
 | 
	
		
			
				|  |  | -+  if (m_deinterlace)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_image_fx, m_omx_image_fx.GetInputPort());
 | 
	
		
			
				|  |  | -+    m_omx_tunnel_image_fx.Initialize(&m_omx_image_fx, m_omx_image_fx.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_omx_tunnel_decoder.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  omx_err = m_omx_tunnel.Establish();
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_tunnel_decoder.Establish();
 | 
	
		
			
				|  |  | -   if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_decoder.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  if (m_deinterlace)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_tunnel_image_fx.Establish();
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - m_omx_tunnel_image_fx.Establish omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_image_fx.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s - m_omx_image_fx.SetStateForComponent omx_err(0x%08x)",
 | 
	
		
			
				|  |  | -+      CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // Obtain the information about the output port.
 | 
	
		
			
				|  |  | -   OMX_PARAM_PORTDEFINITIONTYPE port_format;
 | 
	
		
			
				|  |  | -   OMX_INIT_STRUCTURE(port_format);
 | 
	
		
			
				|  |  | -@@ -724,8 +799,12 @@ void COpenMaxVideo::Reset(void)
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | --  m_omx_egl_render.FlushAll();
 | 
	
		
			
				|  |  | --  m_omx_decoder.FlushAll();
 | 
	
		
			
				|  |  | -+  if (m_omx_egl_render.IsInitialized())
 | 
	
		
			
				|  |  | -+    m_omx_egl_render.FlushAll();
 | 
	
		
			
				|  |  | -+  if (m_omx_image_fx.IsInitialized())
 | 
	
		
			
				|  |  | -+    m_omx_image_fx.FlushAll();
 | 
	
		
			
				|  |  | -+  if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -+    m_omx_decoder.FlushAll();
 | 
	
		
			
				|  |  | -   // blow all ready video frames
 | 
	
		
			
				|  |  | -   while (!m_omx_output_ready.empty())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -825,11 +904,14 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | --    if (!m_dts_queue.empty())
 | 
	
		
			
				|  |  | -+    if (!m_deinterlace_second_field)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -+      assert(!m_dts_queue.empty());
 | 
	
		
			
				|  |  | -       pDvdVideoPicture->dts = m_dts_queue.front();
 | 
	
		
			
				|  |  | -       m_dts_queue.pop();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+    if (m_deinterlace)
 | 
	
		
			
				|  |  | -+      m_deinterlace_second_field = !m_deinterlace_second_field;
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -     // nTimeStamp is in microseconds
 | 
	
		
			
				|  |  | -     double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -index 9138a20..c8ad4d8 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -@@ -31,6 +31,7 @@
 | 
	
		
			
				|  |  | - #include "cores/dvdplayer/DVDStreamInfo.h"
 | 
	
		
			
				|  |  | - #include "DVDVideoCodec.h"
 | 
	
		
			
				|  |  | - #include "threads/Event.h"
 | 
	
		
			
				|  |  | -+#include "xbmc/settings/VideoSettings.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include <queue>
 | 
	
		
			
				|  |  | - #include <semaphore.h>
 | 
	
		
			
				|  |  | -@@ -136,11 +137,17 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Components
 | 
	
		
			
				|  |  | -   COMXCoreComponent m_omx_decoder;
 | 
	
		
			
				|  |  | -+  COMXCoreComponent m_omx_image_fx;
 | 
	
		
			
				|  |  | -   COMXCoreComponent m_omx_egl_render;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  COMXCoreTunel     m_omx_tunnel;
 | 
	
		
			
				|  |  | -+  COMXCoreTunel     m_omx_tunnel_decoder;
 | 
	
		
			
				|  |  | -+  COMXCoreTunel     m_omx_tunnel_image_fx;
 | 
	
		
			
				|  |  | -   OMX_VIDEO_CODINGTYPE m_codingType;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  bool              m_deinterlace;
 | 
	
		
			
				|  |  | -+  EDEINTERLACEMODE  m_deinterlace_request;
 | 
	
		
			
				|  |  | -+  bool              m_deinterlace_second_field;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   bool PortSettingsChanged();
 | 
	
		
			
				|  |  | -   bool SendDecoderConfig(uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | -   bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 0701b41709e6a18567b9f6bfd0d491285546eedc Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Ben Avison <bavison@riscosopen.org>
 | 
	
		
			
				|  |  | -Date: Wed, 12 Feb 2014 18:43:14 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 49/94] Improved file buffering in CArchive.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -CArchive already did some file buffering, but only on writes. Added the
 | 
	
		
			
				|  |  | -equivalent code for reads. Also improved the write buffer case so that it
 | 
	
		
			
				|  |  | -only ever issues sector-aligned writes (the read code does this from the
 | 
	
		
			
				|  |  | -start). Shuffled various bits of code into the header file to squeeze a bit
 | 
	
		
			
				|  |  | -more performance out of it.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Profiled the effect on CFileItemList::Archive(), which is one of the slow
 | 
	
		
			
				|  |  | -parts of the process of reopening a media library, on a non-overclocked
 | 
	
		
			
				|  |  | -Raspberry Pi. Times are in seconds:
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -TV shows (253 items)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Before          After
 | 
	
		
			
				|  |  | -Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -0.394  0.005    0.151  0.005   100.0%      +159.8%
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Songs (4115 items)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Before          After
 | 
	
		
			
				|  |  | -Mean   StdDev   Mean   StdDev  Confidence  Change
 | 
	
		
			
				|  |  | -2.931  0.045    0.690  0.019   100.0%      +324.4%
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/utils/Archive.cpp | 158 ++++++++++++++++++-------------------------------
 | 
	
		
			
				|  |  | - xbmc/utils/Archive.h   | 130 ++++++++++++++++++++++++++++++++++------
 | 
	
		
			
				|  |  | - 2 files changed, 172 insertions(+), 116 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/utils/Archive.cpp b/xbmc/utils/Archive.cpp
 | 
	
		
			
				|  |  | -index 4519e19..b2ad273 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/utils/Archive.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/utils/Archive.cpp
 | 
	
		
			
				|  |  | -@@ -30,24 +30,29 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - using namespace XFILE;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --#define BUFFER_MAX 4096
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - CArchive::CArchive(CFile* pFile, int mode)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_pFile = pFile;
 | 
	
		
			
				|  |  | -   m_iMode = mode;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_pBuffer = new uint8_t[BUFFER_MAX];
 | 
	
		
			
				|  |  | --  memset(m_pBuffer, 0, BUFFER_MAX);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_BufferPos = 0;
 | 
	
		
			
				|  |  | -+  m_pBuffer = new uint8_t[CARCHIVE_BUFFER_MAX];
 | 
	
		
			
				|  |  | -+  memset(m_pBuffer, 0, CARCHIVE_BUFFER_MAX);
 | 
	
		
			
				|  |  | -+  if (mode == load)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_BufferPos = m_pBuffer + CARCHIVE_BUFFER_MAX;
 | 
	
		
			
				|  |  | -+    m_BufferRemain = 0;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_BufferPos = m_pBuffer;
 | 
	
		
			
				|  |  | -+    m_BufferRemain = CARCHIVE_BUFFER_MAX;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - CArchive::~CArchive()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   FlushBuffer();
 | 
	
		
			
				|  |  | -   delete[] m_pBuffer;
 | 
	
		
			
				|  |  | --  m_BufferPos = 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CArchive::Close()
 | 
	
		
			
				|  |  | -@@ -214,89 +219,6 @@ CArchive& CArchive::operator<<(const std::vector<int>& iArray)
 | 
	
		
			
				|  |  | -   return *this;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --inline CArchive& CArchive::streamout(const void* dataPtr, size_t size)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  const uint8_t* ptr = (const uint8_t*)dataPtr;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (size + m_BufferPos >= BUFFER_MAX)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    FlushBuffer();
 | 
	
		
			
				|  |  | --    while (size >= BUFFER_MAX)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      memcpy(m_pBuffer, ptr, BUFFER_MAX);
 | 
	
		
			
				|  |  | --      m_BufferPos = BUFFER_MAX;
 | 
	
		
			
				|  |  | --      ptr += BUFFER_MAX;
 | 
	
		
			
				|  |  | --      size -= BUFFER_MAX;
 | 
	
		
			
				|  |  | --      FlushBuffer();
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  memcpy(m_pBuffer + m_BufferPos, ptr, size);
 | 
	
		
			
				|  |  | --  m_BufferPos += size;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return *this;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(float& f)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&f, sizeof(f));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(double& d)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&d, sizeof(d));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(short int& s)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&s, sizeof(s));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(unsigned short int& us)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&us, sizeof(us));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(int& i)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&i, sizeof(i));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(unsigned int& ui)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&ui, sizeof(ui));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(long int& l)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&l, sizeof(l));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(unsigned long int& ul)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&ul, sizeof(ul));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(long long int& ll)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&ll, sizeof(ll));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(unsigned long long int& ull)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&ull, sizeof(ull));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(bool& b)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&b, sizeof(b));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CArchive& CArchive::operator>>(char& c)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return streamin(&c, sizeof(c));
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - CArchive& CArchive::operator>>(std::string& str)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   size_t iLength = 0;
 | 
	
		
			
				|  |  | -@@ -450,23 +372,61 @@ CArchive& CArchive::operator>>(std::vector<int>& iArray)
 | 
	
		
			
				|  |  | -   return *this;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --inline CArchive& CArchive::streamin(void* dataPtr, const size_t size)
 | 
	
		
			
				|  |  | -+void CArchive::FlushBuffer()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  size_t read = m_pFile->Read(dataPtr, size);
 | 
	
		
			
				|  |  | --  if (read < size)
 | 
	
		
			
				|  |  | -+  if (m_iMode == store && m_BufferPos != m_pBuffer)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s: can't stream out: requested %lu bytes, was read %lu bytes", __FUNCTION__, (unsigned long)size, (unsigned long)read);
 | 
	
		
			
				|  |  | --    memset(dataPtr, 0, size);
 | 
	
		
			
				|  |  | -+    m_pFile->Write(m_pBuffer, m_BufferPos - m_pBuffer);
 | 
	
		
			
				|  |  | -+    m_BufferPos = m_pBuffer;
 | 
	
		
			
				|  |  | -+    m_BufferRemain = CARCHIVE_BUFFER_MAX;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+CArchive &CArchive::streamout_bufferwrap(const uint8_t *ptr, size_t size)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  do
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    size_t chunkSize = std::min(size, m_BufferRemain);
 | 
	
		
			
				|  |  | -+    m_BufferPos = std::copy(ptr, ptr + chunkSize, m_BufferPos);
 | 
	
		
			
				|  |  | -+    ptr += chunkSize;
 | 
	
		
			
				|  |  | -+    size -= chunkSize;
 | 
	
		
			
				|  |  | -+    m_BufferRemain -= chunkSize;
 | 
	
		
			
				|  |  | -+    if (m_BufferRemain == 0)
 | 
	
		
			
				|  |  | -+      FlushBuffer();
 | 
	
		
			
				|  |  | -+  } while (size > 0);
 | 
	
		
			
				|  |  | -   return *this;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CArchive::FlushBuffer()
 | 
	
		
			
				|  |  | -+void CArchive::FillBuffer()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if (m_BufferPos > 0)
 | 
	
		
			
				|  |  | -+  if (m_iMode == load && m_BufferRemain == 0)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    m_pFile->Write(m_pBuffer, m_BufferPos);
 | 
	
		
			
				|  |  | --    m_BufferPos = 0;
 | 
	
		
			
				|  |  | -+    m_BufferRemain = m_pFile->Read(m_pBuffer, CARCHIVE_BUFFER_MAX);
 | 
	
		
			
				|  |  | -+    m_BufferPos = m_pBuffer;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CArchive &CArchive::streamin_bufferwrap(uint8_t *ptr, size_t size)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  uint8_t *orig_ptr = ptr;
 | 
	
		
			
				|  |  | -+  size_t orig_size = size;
 | 
	
		
			
				|  |  | -+  do
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (m_BufferRemain == 0)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      FillBuffer();
 | 
	
		
			
				|  |  | -+      if (m_BufferRemain < CARCHIVE_BUFFER_MAX && m_BufferRemain < size)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s: can't stream in: requested %lu bytes, was read %lu bytes", __FUNCTION__, (unsigned long) orig_size, (unsigned long) (ptr - orig_ptr + m_BufferRemain));
 | 
	
		
			
				|  |  | -+        memset(orig_ptr, 0, orig_size);
 | 
	
		
			
				|  |  | -+        return *this;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    size_t chunkSize = std::min(size, m_BufferRemain);
 | 
	
		
			
				|  |  | -+    ptr = std::copy(m_BufferPos, m_BufferPos + chunkSize, ptr);
 | 
	
		
			
				|  |  | -+    m_BufferPos += chunkSize;
 | 
	
		
			
				|  |  | -+    m_BufferRemain -= chunkSize;
 | 
	
		
			
				|  |  | -+    size -= chunkSize;
 | 
	
		
			
				|  |  | -+  } while (size > 0);
 | 
	
		
			
				|  |  | -+  return *this;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/utils/Archive.h b/xbmc/utils/Archive.h
 | 
	
		
			
				|  |  | -index 0148fcb..5b25be5 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/utils/Archive.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/utils/Archive.h
 | 
	
		
			
				|  |  | -@@ -24,6 +24,8 @@
 | 
	
		
			
				|  |  | - #include <vector>
 | 
	
		
			
				|  |  | - #include "PlatformDefs.h" // for SYSTEMTIME
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#define CARCHIVE_BUFFER_MAX 4096
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - namespace XFILE
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   class CFile;
 | 
	
		
			
				|  |  | -@@ -77,18 +79,66 @@ class CArchive
 | 
	
		
			
				|  |  | -   CArchive& operator<<(const std::vector<int>& iArray);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // loading
 | 
	
		
			
				|  |  | --  CArchive& operator>>(float& f);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(double& d);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(short int& s);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(unsigned short int& us);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(int& i);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(unsigned int& ui);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(long int& l);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(unsigned long int& ul);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(long long int& ll);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(unsigned long long int& ull);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(bool& b);
 | 
	
		
			
				|  |  | --  CArchive& operator>>(char& c);
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(float& f)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&f, sizeof(f));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(double& d)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&d, sizeof(d));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(short int& s)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&s, sizeof(s));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(unsigned short int& us)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&us, sizeof(us));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(int& i)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&i, sizeof(i));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(unsigned int& ui)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&ui, sizeof(ui));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(long int& l)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&l, sizeof(l));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(unsigned long int& ul)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&ul, sizeof(ul));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(long long int& ll)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&ll, sizeof(ll));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(unsigned long long int& ull)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&ull, sizeof(ull));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(bool& b)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&b, sizeof(b));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive& operator>>(char& c)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    return streamin(&c, sizeof(c));
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   CArchive& operator>>(std::string &str);
 | 
	
		
			
				|  |  | -   CArchive& operator>>(std::wstring& wstr);
 | 
	
		
			
				|  |  | -   CArchive& operator>>(SYSTEMTIME& time);
 | 
	
		
			
				|  |  | -@@ -105,12 +155,58 @@ class CArchive
 | 
	
		
			
				|  |  | -   enum Mode {load = 0, store};
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | --  CArchive& streamout(const void* dataPtr, size_t size);
 | 
	
		
			
				|  |  | --  CArchive& streamin(void* dataPtr, const size_t size);
 | 
	
		
			
				|  |  | --  void FlushBuffer();
 | 
	
		
			
				|  |  | -+  inline CArchive &streamout(const void *dataPtr, size_t size)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    const uint8_t *ptr = (const uint8_t *) dataPtr;
 | 
	
		
			
				|  |  | -+    /* Note, the buffer is flushed as soon as it is full (m_BufferRemain == size) rather
 | 
	
		
			
				|  |  | -+     * than waiting until we attempt to put more data into an already full buffer */
 | 
	
		
			
				|  |  | -+    if (m_BufferRemain > size)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      switch (size)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+      case 1: *m_BufferPos++ = *ptr; m_BufferRemain--; break;
 | 
	
		
			
				|  |  | -+      case 2: *(uint16_t *) m_BufferPos = *(const uint16_t *) ptr; m_BufferPos += 2; m_BufferRemain -= 2; break;
 | 
	
		
			
				|  |  | -+      case 4: *(uint32_t *) m_BufferPos = *(const uint32_t *) ptr; m_BufferPos += 4; m_BufferRemain -= 4; break;
 | 
	
		
			
				|  |  | -+      default: m_BufferPos = std::copy(ptr, ptr + size, m_BufferPos); m_BufferRemain -= size; break;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      return *this;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      return streamout_bufferwrap(ptr, size);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  inline CArchive &streamin(void *dataPtr, size_t size)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    uint8_t *ptr = (uint8_t *) dataPtr;
 | 
	
		
			
				|  |  | -+    /* Note, refilling the buffer is deferred until we know we need to read more from it */
 | 
	
		
			
				|  |  | -+    if (m_BufferRemain >= size)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      switch (size)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+      case 1: *ptr = *m_BufferPos++; m_BufferRemain--; break;
 | 
	
		
			
				|  |  | -+      case 2: *(uint16_t *) ptr = *(const uint16_t *) m_BufferPos; m_BufferPos += 2; m_BufferRemain -= 2; break;
 | 
	
		
			
				|  |  | -+      case 4: *(uint32_t *) ptr = *(const uint32_t *) m_BufferPos; m_BufferPos += 4; m_BufferRemain -= 4; break;
 | 
	
		
			
				|  |  | -+      default: std::copy(m_BufferPos, m_BufferPos + size, ptr); m_BufferPos += size; m_BufferRemain -= size; break;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      return *this;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      return streamin_bufferwrap(ptr, size);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   XFILE::CFile* m_pFile;
 | 
	
		
			
				|  |  | -   int m_iMode;
 | 
	
		
			
				|  |  | -   uint8_t *m_pBuffer;
 | 
	
		
			
				|  |  | --  int m_BufferPos;
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | -+  uint8_t *m_BufferPos;
 | 
	
		
			
				|  |  | -+  size_t m_BufferRemain;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+private:
 | 
	
		
			
				|  |  | -+  void FlushBuffer();
 | 
	
		
			
				|  |  | -+  CArchive &streamout_bufferwrap(const uint8_t *ptr, size_t size);
 | 
	
		
			
				|  |  | -+  void FillBuffer();
 | 
	
		
			
				|  |  | -+  CArchive &streamin_bufferwrap(uint8_t *ptr, size_t size);
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 2ae9667952e98ab91b0056094231e923570fa64b Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 5 Feb 2014 11:46:33 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 50/94] [rbp/settings] Allow av sync type to be enabled
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -It works for dvdplayer
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - system/settings/rbp.xml | 7 -------
 | 
	
		
			
				|  |  | - 1 file changed, 7 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/system/settings/rbp.xml b/system/settings/rbp.xml
 | 
	
		
			
				|  |  | -index 2b7d0a6..1429256 100644
 | 
	
		
			
				|  |  | ---- a/system/settings/rbp.xml
 | 
	
		
			
				|  |  | -+++ b/system/settings/rbp.xml
 | 
	
		
			
				|  |  | -@@ -1,13 +1,6 @@
 | 
	
		
			
				|  |  | - <?xml version="1.0" encoding="utf-8" ?>
 | 
	
		
			
				|  |  | - <settings>
 | 
	
		
			
				|  |  | -   <section id="videos">
 | 
	
		
			
				|  |  | --    <category id="videoplayer">
 | 
	
		
			
				|  |  | --      <group id="2">
 | 
	
		
			
				|  |  | --        <setting id="videoplayer.synctype">
 | 
	
		
			
				|  |  | --          <visible>false</visible>
 | 
	
		
			
				|  |  | --        </setting>
 | 
	
		
			
				|  |  | --      </group>
 | 
	
		
			
				|  |  | --    </category>
 | 
	
		
			
				|  |  | -     <category id="videoacceleration">
 | 
	
		
			
				|  |  | -       <group id="1">
 | 
	
		
			
				|  |  | -         <visible>false</visible>
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 4fb1419b986a36f2e53a5bca71caf90bd13443ba Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sun, 16 Feb 2014 17:38:05 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 51/94] [omxcodec] Only do essential calls in texture thread
 | 
	
		
			
				|  |  | - [omxcodec] Fix for files with no valid pts values. [omxcodec] Fix stall on
 | 
	
		
			
				|  |  | - seek/trickplay - need to reset start flag [omxcodec] Make sure we have a
 | 
	
		
			
				|  |  | - valid context when video decode starts before first fanart is decoded
 | 
	
		
			
				|  |  | - [omxcodec] More care with dropping frames quickly
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp     | 127 ++++++++++++++-------
 | 
	
		
			
				|  |  | - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h |  14 +--
 | 
	
		
			
				|  |  | - 2 files changed, 89 insertions(+), 52 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index fbf1458..71d19af 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -55,6 +55,9 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define CLASSNAME "COpenMaxVideo"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#define OMX_BUFFERFLAG_PTS_INVALID (1<<28)
 | 
	
		
			
				|  |  | -+#define OMX_BUFFERFLAG_DROPPED     (1<<29)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
 | 
	
		
			
				|  |  | -     : m_omv(omv), m_refs(0)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -@@ -120,7 +123,9 @@ void COpenMaxVideoBuffer::Sync()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - COpenMaxVideo::COpenMaxVideo()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+  #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "%s::%s %p", CLASSNAME, __func__, this);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -   pthread_mutex_init(&m_omx_output_mutex, NULL);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_drop_state = false;
 | 
	
		
			
				|  |  | -@@ -135,6 +140,7 @@ COpenMaxVideo::COpenMaxVideo()
 | 
	
		
			
				|  |  | -   m_deinterlace = false;
 | 
	
		
			
				|  |  | -   m_deinterlace_request = VS_DEINTERLACEMODE_OFF;
 | 
	
		
			
				|  |  | -   m_deinterlace_second_field = false;
 | 
	
		
			
				|  |  | -+  m_startframe = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | -@@ -182,8 +188,6 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
 | 
	
		
			
				|  |  | -   m_forced_aspect_ratio = hints.forced_aspect;
 | 
	
		
			
				|  |  | -   m_aspect_ratio = hints.aspect;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_egl_display = g_Windowing.GetEGLDisplay();
 | 
	
		
			
				|  |  | --  m_egl_context = g_Windowing.GetEGLContext();
 | 
	
		
			
				|  |  | -   m_egl_buffer_count = 4;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_codingType = OMX_VIDEO_CodingUnused;
 | 
	
		
			
				|  |  | -@@ -347,6 +351,7 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_drop_state = false;
 | 
	
		
			
				|  |  | -+  m_startframe = false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -@@ -375,6 +380,25 @@ void COpenMaxVideo::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | -       CLASSNAME, __func__, bDrop);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -   m_drop_state = bDrop;
 | 
	
		
			
				|  |  | -+  if (m_drop_state)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    while (1)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      COpenMaxVideoBuffer *buffer = NULL;
 | 
	
		
			
				|  |  | -+      pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+      // fetch a output buffer and pop it off the ready list
 | 
	
		
			
				|  |  | -+      if (!m_omx_output_ready.empty())
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        buffer = m_omx_output_ready.front();
 | 
	
		
			
				|  |  | -+        m_omx_output_ready.pop();
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+      if (buffer)
 | 
	
		
			
				|  |  | -+        ReturnOpenMaxBuffer(buffer);
 | 
	
		
			
				|  |  | -+      else
 | 
	
		
			
				|  |  | -+        break;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool COpenMaxVideo::SendDecoderConfig(uint8_t *extradata, int extrasize)
 | 
	
		
			
				|  |  | -@@ -713,10 +737,13 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       if (demuxer_bytes == 0)
 | 
	
		
			
				|  |  | -         omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
 | 
	
		
			
				|  |  | --      if (pts == DVD_NOPTS_VALUE)
 | 
	
		
			
				|  |  | -+      // openmax doesn't like an unknown timestamp as first frame
 | 
	
		
			
				|  |  | -+      if (pts == DVD_NOPTS_VALUE && m_startframe)
 | 
	
		
			
				|  |  | -         omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
 | 
	
		
			
				|  |  | -+      if (pts == DVD_NOPTS_VALUE) // hijack an omx flag to indicate there wasn't a real timestamp - it will be returned with the picture (but otherwise ignored)
 | 
	
		
			
				|  |  | -+        omx_buffer->nFlags |= OMX_BUFFERFLAG_PTS_INVALID;
 | 
	
		
			
				|  |  | -       if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
 | 
	
		
			
				|  |  | --        omx_buffer->nFlags |= OMX_BUFFERFLAG_DATACORRUPT;
 | 
	
		
			
				|  |  | -+        omx_buffer->nFlags |= OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -       CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x",
 | 
	
		
			
				|  |  | -@@ -731,10 +758,14 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -       if (demuxer_bytes == 0)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -+        m_startframe = true;
 | 
	
		
			
				|  |  | - #ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | --        // only push if we are successful with feeding OMX_EmptyThisBuffer
 | 
	
		
			
				|  |  | --        m_dts_queue.push(dts);
 | 
	
		
			
				|  |  | --        assert(m_dts_queue.size() < 32);
 | 
	
		
			
				|  |  | -+        if (!m_drop_state)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          // only push if we are successful with feeding OMX_EmptyThisBuffer
 | 
	
		
			
				|  |  | -+          m_dts_queue.push(dts);
 | 
	
		
			
				|  |  | -+          assert(m_dts_queue.size() < 32);
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -         if (buffer_to_free)
 | 
	
		
			
				|  |  | -         {
 | 
	
		
			
				|  |  | -@@ -806,15 +837,8 @@ void COpenMaxVideo::Reset(void)
 | 
	
		
			
				|  |  | -   if (m_omx_decoder.IsInitialized())
 | 
	
		
			
				|  |  | -     m_omx_decoder.FlushAll();
 | 
	
		
			
				|  |  | -   // blow all ready video frames
 | 
	
		
			
				|  |  | --  while (!m_omx_output_ready.empty())
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | --    COpenMaxVideoBuffer *pic = m_omx_output_ready.front();
 | 
	
		
			
				|  |  | --    m_omx_output_ready.pop();
 | 
	
		
			
				|  |  | --    pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | --    // return the omx buffer back to OpenMax to fill.
 | 
	
		
			
				|  |  | --    ReturnOpenMaxBuffer(pic);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+  SetDropState(true);
 | 
	
		
			
				|  |  | -+  SetDropState(false);
 | 
	
		
			
				|  |  | - #ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -   while (!m_dts_queue.empty())
 | 
	
		
			
				|  |  | -     m_dts_queue.pop();
 | 
	
		
			
				|  |  | -@@ -822,6 +846,7 @@ void COpenMaxVideo::Reset(void)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   while (!m_demux_queue.empty())
 | 
	
		
			
				|  |  | -     m_demux_queue.pop();
 | 
	
		
			
				|  |  | -+  m_startframe = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -914,17 +939,17 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -       m_deinterlace_second_field = !m_deinterlace_second_field;
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -     // nTimeStamp is in microseconds
 | 
	
		
			
				|  |  | --    double ts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
 | 
	
		
			
				|  |  | --    pDvdVideoPicture->pts = (ts == 0) ? DVD_NOPTS_VALUE : ts;
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->pts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->openMaxBuffer->Acquire();
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->iFlags  = DVP_FLAG_ALLOCATED;
 | 
	
		
			
				|  |  | --    if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_DATACORRUPT)
 | 
	
		
			
				|  |  | --      pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
 | 
	
		
			
				|  |  | -+    if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_PTS_INVALID)
 | 
	
		
			
				|  |  | -+      pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | - #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | -     CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -         pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6,
 | 
	
		
			
				|  |  | -         pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -+    assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -953,10 +978,11 @@ OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
 | 
	
		
			
				|  |  | -   COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f",
 | 
	
		
			
				|  |  | --    CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x",
 | 
	
		
			
				|  |  | -+    CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
 | 
	
		
			
				|  |  | -   // queue output omx buffer to ready list.
 | 
	
		
			
				|  |  | -   pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -   buffer->m_aspect_ratio = m_aspect_ratio;
 | 
	
		
			
				|  |  | -@@ -1000,41 +1026,60 @@ OMX_ERRORTYPE COpenMaxVideo::FreeOMXInputBuffers(void)
 | 
	
		
			
				|  |  | -   return(omx_err);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --bool COpenMaxVideo::CallbackAllocOMXEGLTextures(void *userdata)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::CallbackAllocOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void *userdata)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
 | 
	
		
			
				|  |  | --  return omx->AllocOMXOutputEGLTextures() == OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+  return omx->AllocOMXOutputEGLTextures(egl_display, egl_context) == OMX_ErrorNone;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --bool COpenMaxVideo::CallbackFreeOMXEGLTextures(void *userdata)
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::CallbackFreeOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void *userdata)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   COpenMaxVideo *omx = static_cast<COpenMaxVideo*>(userdata);
 | 
	
		
			
				|  |  | --  return omx->FreeOMXOutputEGLTextures() == OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+  return omx->FreeOMXOutputEGLTextures(egl_display, egl_context) == OMX_ErrorNone;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool COpenMaxVideo::AllocOMXOutputBuffers(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  return g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this);
 | 
	
		
			
				|  |  | -+  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  for (size_t i = 0; i < m_egl_buffer_count; i++)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    COpenMaxVideoBuffer *egl_buffer = new COpenMaxVideoBuffer(this);
 | 
	
		
			
				|  |  | -+    egl_buffer->width  = m_decoded_width;
 | 
	
		
			
				|  |  | -+    egl_buffer->height = m_decoded_height;
 | 
	
		
			
				|  |  | -+    egl_buffer->index = i;
 | 
	
		
			
				|  |  | -+    m_omx_output_buffers.push_back(egl_buffer);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  bool ret = g_OMXImage.SendMessage(CallbackAllocOMXEGLTextures, (void *)this);
 | 
	
		
			
				|  |  | -+  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool COpenMaxVideo::FreeOMXOutputBuffers(void)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  return g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this);
 | 
	
		
			
				|  |  | -+  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  bool ret = g_OMXImage.SendMessage(CallbackFreeOMXEGLTextures, (void *)this);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i];
 | 
	
		
			
				|  |  | -+    delete egl_buffer;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_omx_output_buffers.clear();
 | 
	
		
			
				|  |  | -+  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | -+OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -   EGLint attrib = EGL_NONE;
 | 
	
		
			
				|  |  | --  COpenMaxVideoBuffer *egl_buffer;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   glActiveTexture(GL_TEXTURE0);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   for (size_t i = 0; i < m_egl_buffer_count; i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    egl_buffer = new COpenMaxVideoBuffer(this);
 | 
	
		
			
				|  |  | --    egl_buffer->width  = m_decoded_width;
 | 
	
		
			
				|  |  | --    egl_buffer->height = m_decoded_height;
 | 
	
		
			
				|  |  | -+    COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i];
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     glGenTextures(1, &egl_buffer->texture_id);
 | 
	
		
			
				|  |  | -     glBindTexture(GL_TEXTURE_2D, egl_buffer->texture_id);
 | 
	
		
			
				|  |  | -@@ -1057,8 +1102,8 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     // create EGLImage from texture
 | 
	
		
			
				|  |  | -     egl_buffer->egl_image = eglCreateImageKHR(
 | 
	
		
			
				|  |  | --      m_egl_display,
 | 
	
		
			
				|  |  | --      m_egl_context,
 | 
	
		
			
				|  |  | -+      egl_display,
 | 
	
		
			
				|  |  | -+      egl_context,
 | 
	
		
			
				|  |  | -       EGL_GL_TEXTURE_2D_KHR,
 | 
	
		
			
				|  |  | -       (EGLClientBuffer)(egl_buffer->texture_id),
 | 
	
		
			
				|  |  | -       &attrib);
 | 
	
		
			
				|  |  | -@@ -1067,7 +1112,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | -       CLog::Log(LOGERROR, "%s::%s - ERROR creating EglImage", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -       return(OMX_ErrorUndefined);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    egl_buffer->index = i;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     // tell decoder output port that it will be using EGLImage
 | 
	
		
			
				|  |  | -     omx_err = m_omx_egl_render.UseEGLImage(
 | 
	
		
			
				|  |  | -@@ -1078,7 +1122,6 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | -         CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -       return(omx_err);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --    m_omx_output_buffers.push_back(egl_buffer);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     CLog::Log(LOGDEBUG, "%s::%s - Texture %p Width %d Height %d",
 | 
	
		
			
				|  |  | -       CLASSNAME, __func__, egl_buffer->egl_image, egl_buffer->width, egl_buffer->height);
 | 
	
		
			
				|  |  | -@@ -1086,26 +1129,22 @@ OMX_ERRORTYPE COpenMaxVideo::AllocOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | -   return omx_err;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(void)
 | 
	
		
			
				|  |  | -+OMX_ERRORTYPE COpenMaxVideo::FreeOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --  COpenMaxVideoBuffer *egl_buffer;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   for (size_t i = 0; i < m_omx_output_buffers.size(); i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    egl_buffer = m_omx_output_buffers[i];
 | 
	
		
			
				|  |  | -+    COpenMaxVideoBuffer *egl_buffer = m_omx_output_buffers[i];
 | 
	
		
			
				|  |  | -     // tell decoder output port to stop using the EGLImage
 | 
	
		
			
				|  |  | -     omx_err = m_omx_egl_render.FreeOutputBuffer(egl_buffer->omx_buffer);
 | 
	
		
			
				|  |  | -     if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -       CLog::Log(LOGERROR, "%s::%s m_omx_egl_render.FreeOutputBuffer(%p) omx_err(0x%08x)", CLASSNAME, __func__, egl_buffer->omx_buffer, omx_err);
 | 
	
		
			
				|  |  | -     // destroy egl_image
 | 
	
		
			
				|  |  | --    eglDestroyImageKHR(m_egl_display, egl_buffer->egl_image);
 | 
	
		
			
				|  |  | -+    eglDestroyImageKHR(egl_display, egl_buffer->egl_image);
 | 
	
		
			
				|  |  | -     // free texture
 | 
	
		
			
				|  |  | -     glDeleteTextures(1, &egl_buffer->texture_id);
 | 
	
		
			
				|  |  | --    delete egl_buffer;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  m_omx_output_buffers.clear();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   return omx_err;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -index c8ad4d8..f234f6d 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -@@ -99,17 +99,13 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE FreeOMXInputBuffers(void);
 | 
	
		
			
				|  |  | -   bool AllocOMXOutputBuffers(void);
 | 
	
		
			
				|  |  | -   bool FreeOMXOutputBuffers(void);
 | 
	
		
			
				|  |  | --  static bool CallbackAllocOMXEGLTextures(void*);
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE AllocOMXOutputEGLTextures(void);
 | 
	
		
			
				|  |  | --  static bool CallbackFreeOMXEGLTextures(void*);
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE FreeOMXOutputEGLTextures(void);
 | 
	
		
			
				|  |  | -+  static bool CallbackAllocOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void*);
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE AllocOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context);
 | 
	
		
			
				|  |  | -+  static bool CallbackFreeOMXEGLTextures(EGLDisplay egl_display, EGLContext egl_context, void*);
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE FreeOMXOutputEGLTextures(EGLDisplay egl_display, EGLContext egl_context);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE StopDecoder(void);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE ReturnOpenMaxBuffer(COpenMaxVideoBuffer *buffer);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // EGL Resources
 | 
	
		
			
				|  |  | --  EGLDisplay        m_egl_display;
 | 
	
		
			
				|  |  | --  EGLContext        m_egl_context;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   // Video format
 | 
	
		
			
				|  |  | -   bool              m_drop_state;
 | 
	
		
			
				|  |  | -   int               m_decoded_width;
 | 
	
		
			
				|  |  | -@@ -148,6 +144,8 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | -   EDEINTERLACEMODE  m_deinterlace_request;
 | 
	
		
			
				|  |  | -   bool              m_deinterlace_second_field;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  bool              m_startframe;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   bool PortSettingsChanged();
 | 
	
		
			
				|  |  | -   bool SendDecoderConfig(uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | -   bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 182b137323347482bfca46dbb857813e4f984298 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 1 Mar 2014 14:24:08 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 52/94] [omxplayer] Allow small audio packets to be
 | 
	
		
			
				|  |  | - concatenated to make better use of audio fifo
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Some audio codecs produce small packets which causes a high overhead when submitting to GPU, and doesn't make full use of GPU side buffering.
 | 
	
		
			
				|  |  | -TrueHD in particular can produce packets with 40 samples (so 1200 packets per second) which causes very high overhead.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -What this aims to do is to concatenate audio packets until they approach the ideal audio packet size,
 | 
	
		
			
				|  |  | -and then deal with the awkardness of concatenated planar formats.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudio.cpp         | 67 +++++++++++++++++++---------
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudio.h           |  3 +-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp | 72 +++++++++++++++++++++----------
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudioCodecOMX.h   |  9 +++-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerAudio.cpp   |  9 ++--
 | 
	
		
			
				|  |  | - 5 files changed, 110 insertions(+), 50 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -index dd80412..e67dc94 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -@@ -43,6 +43,10 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - using namespace std;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+// the size of the audio_render output port buffers
 | 
	
		
			
				|  |  | -+#define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
 | 
	
		
			
				|  |  | -+static const char rounded_up_channels_shift[] = {0,0,1,2,2,3,3,3,3};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - static const uint16_t AC3Bitrates[] = {32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640};
 | 
	
		
			
				|  |  | - static const uint16_t AC3FSCod   [] = {48000, 44100, 32000, 0};
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -61,6 +65,7 @@ COMXAudio::COMXAudio() :
 | 
	
		
			
				|  |  | -   m_Passthrough     (false  ),
 | 
	
		
			
				|  |  | -   m_HWDecode        (false  ),
 | 
	
		
			
				|  |  | -   m_BytesPerSec     (0      ),
 | 
	
		
			
				|  |  | -+  m_InputBytesPerSec(0      ),
 | 
	
		
			
				|  |  | -   m_BufferLen       (0      ),
 | 
	
		
			
				|  |  | -   m_ChunkLen        (0      ),
 | 
	
		
			
				|  |  | -   m_InputChannels   (0      ),
 | 
	
		
			
				|  |  | -@@ -490,11 +495,15 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_SampleRate    = m_format.m_sampleRate;
 | 
	
		
			
				|  |  | -   m_BitsPerSample = CAEUtil::DataFormatToBits(m_format.m_dataFormat);
 | 
	
		
			
				|  |  | --  m_BufferLen     = m_BytesPerSec = m_format.m_sampleRate * (16 >> 3) * m_InputChannels;
 | 
	
		
			
				|  |  | --  m_BufferLen     *= AUDIO_BUFFER_SECONDS;
 | 
	
		
			
				|  |  | -+  m_BytesPerSec   = m_SampleRate * 2 << rounded_up_channels_shift[m_InputChannels];
 | 
	
		
			
				|  |  | -+  m_BufferLen     = m_BytesPerSec * AUDIO_BUFFER_SECONDS;
 | 
	
		
			
				|  |  | -+  m_InputBytesPerSec = m_SampleRate * m_BitsPerSample * m_InputChannels >> 3;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // should be big enough that common formats (e.g. 6 channel DTS) fit in a single packet.
 | 
	
		
			
				|  |  | -+  // we don't mind less common formats being split (e.g. ape/wma output large frames)
 | 
	
		
			
				|  |  | -   // the audio_decode output buffer size is 32K, and typically we convert from
 | 
	
		
			
				|  |  | --  // 6 channel 32bpp float to 8 channel 16bpp in, so a full 48K input buffer will fit the outbut buffer
 | 
	
		
			
				|  |  | --  m_ChunkLen      = 48*1024;
 | 
	
		
			
				|  |  | -+  // 6 channel 32bpp float to 8 channel 16bpp in, so a full 48K input buffer will fit the output buffer
 | 
	
		
			
				|  |  | -+  m_ChunkLen = AUDIO_DECODE_OUTPUT_BUFFER * (m_InputChannels * m_BitsPerSample) >> (rounded_up_channels_shift[m_InputChannels] + 4);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_wave_header.Samples.wSamplesPerBlock    = 0;
 | 
	
		
			
				|  |  | -   m_wave_header.Format.nChannels            = m_InputChannels;
 | 
	
		
			
				|  |  | -@@ -682,7 +691,7 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
 | 
	
		
			
				|  |  | -   m_maxLevel      = 0.0f;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "COMXAudio::Initialize Input bps %d samplerate %d channels %d buffer size %d bytes per second %d",
 | 
	
		
			
				|  |  | --      (int)m_pcm_input.nBitPerSample, (int)m_pcm_input.nSamplingRate, (int)m_pcm_input.nChannels, m_BufferLen, m_BytesPerSec);
 | 
	
		
			
				|  |  | -+      (int)m_pcm_input.nBitPerSample, (int)m_pcm_input.nSamplingRate, (int)m_pcm_input.nChannels, m_BufferLen, m_InputBytesPerSec);
 | 
	
		
			
				|  |  | -   PrintPCM(&m_pcm_input, std::string("input"));
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "COMXAudio::Initialize device passthrough %d hwdecode %d",
 | 
	
		
			
				|  |  | -      m_Passthrough, m_HWDecode);
 | 
	
		
			
				|  |  | -@@ -865,11 +874,11 @@ bool COMXAudio::ApplyVolume(void)
 | 
	
		
			
				|  |  | - //***********************************************************************************************
 | 
	
		
			
				|  |  | - unsigned int COMXAudio::AddPackets(const void* data, unsigned int len)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  return AddPackets(data, len, 0, 0);
 | 
	
		
			
				|  |  | -+  return AddPackets(data, len, 0, 0, 0);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - //***********************************************************************************************
 | 
	
		
			
				|  |  | --unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dts, double pts)
 | 
	
		
			
				|  |  | -+unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dts, double pts, unsigned int frame_size)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   CSingleLock lock (m_critSection);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -916,24 +925,40 @@ unsigned int COMXAudio::AddPackets(const void* data, unsigned int len, double dt
 | 
	
		
			
				|  |  | -     omx_buffer->nOffset = 0;
 | 
	
		
			
				|  |  | -     omx_buffer->nFlags  = 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    // we want audio_decode output buffer size to be no more than AUDIO_DECODE_OUTPUT_BUFFER.
 | 
	
		
			
				|  |  | -+    // it will be 16-bit and rounded up to next power of 2 in channels
 | 
	
		
			
				|  |  | -+    unsigned int max_buffer = AUDIO_DECODE_OUTPUT_BUFFER * (m_InputChannels * m_BitsPerSample) >> (rounded_up_channels_shift[m_InputChannels] + 4);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     unsigned int remaining = demuxer_samples-demuxer_samples_sent;
 | 
	
		
			
				|  |  | --    unsigned int samples_space = omx_buffer->nAllocLen/pitch;
 | 
	
		
			
				|  |  | -+    unsigned int samples_space = std::min(max_buffer, omx_buffer->nAllocLen)/pitch;
 | 
	
		
			
				|  |  | -     unsigned int samples = std::min(remaining, samples_space);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     omx_buffer->nFilledLen = samples * pitch;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    if (samples < demuxer_samples && m_BitsPerSample==32 && !(m_Passthrough || m_HWDecode))
 | 
	
		
			
				|  |  | -+    unsigned int frames = frame_size ? len/frame_size:0;
 | 
	
		
			
				|  |  | -+    if ((samples < demuxer_samples || frames > 1) && m_BitsPerSample==32 && !(m_Passthrough || m_HWDecode))
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --       uint8_t *dst = omx_buffer->pBuffer;
 | 
	
		
			
				|  |  | --       uint8_t *src = demuxer_content + demuxer_samples_sent * (m_BitsPerSample >> 3);
 | 
	
		
			
				|  |  | --       // we need to extract samples from planar audio, so the copying needs to be done per plane
 | 
	
		
			
				|  |  | --       for (int i=0; i<(int)m_InputChannels; i++)
 | 
	
		
			
				|  |  | --       {
 | 
	
		
			
				|  |  | --         memcpy(dst, src, omx_buffer->nFilledLen / m_InputChannels);
 | 
	
		
			
				|  |  | --         dst += omx_buffer->nFilledLen / m_InputChannels;
 | 
	
		
			
				|  |  | --         src += demuxer_samples * (m_BitsPerSample >> 3);
 | 
	
		
			
				|  |  | --       }
 | 
	
		
			
				|  |  | --       assert(dst <= omx_buffer->pBuffer + m_ChunkLen);
 | 
	
		
			
				|  |  | -+      const unsigned int sample_pitch   = m_BitsPerSample >> 3;
 | 
	
		
			
				|  |  | -+      const unsigned int frame_samples  = frame_size / pitch;
 | 
	
		
			
				|  |  | -+      const unsigned int plane_size     = frame_samples * sample_pitch;
 | 
	
		
			
				|  |  | -+      const unsigned int out_plane_size = samples * sample_pitch;
 | 
	
		
			
				|  |  | -+      //CLog::Log(LOGDEBUG, "%s::%s samples:%d/%d ps:%d ops:%d fs:%d pitch:%d filled:%d frames=%d", CLASSNAME, __func__, samples, demuxer_samples, plane_size, out_plane_size, frame_size, pitch, omx_buffer->nFilledLen, frames);
 | 
	
		
			
				|  |  | -+      for (unsigned int sample = 0; sample < samples; )
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        unsigned int frame = (demuxer_samples_sent + sample) / frame_samples;
 | 
	
		
			
				|  |  | -+        unsigned int sample_in_frame = (demuxer_samples_sent + sample) - frame * frame_samples;
 | 
	
		
			
				|  |  | -+        int out_remaining = std::min(std::min(frame_samples - sample_in_frame, samples), samples-sample);
 | 
	
		
			
				|  |  | -+        uint8_t *src = demuxer_content + frame*frame_size + sample_in_frame * sample_pitch;
 | 
	
		
			
				|  |  | -+        uint8_t *dst = (uint8_t *)omx_buffer->pBuffer + sample * sample_pitch;
 | 
	
		
			
				|  |  | -+        for (unsigned int channel = 0; channel < m_InputChannels; channel++)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          //CLog::Log(LOGDEBUG, "%s::%s copy(%d,%d,%d) (s:%d f:%d sin:%d c:%d)", CLASSNAME, __func__, dst-(uint8_t *)omx_buffer->pBuffer, src-demuxer_content, out_remaining, sample, frame, sample_in_frame, channel);
 | 
	
		
			
				|  |  | -+          memcpy(dst, src, out_remaining * sample_pitch);
 | 
	
		
			
				|  |  | -+          src += plane_size;
 | 
	
		
			
				|  |  | -+          dst += out_plane_size;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+        sample += out_remaining;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     else
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -@@ -1114,7 +1139,9 @@ float COMXAudio::GetCacheTime()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - float COMXAudio::GetCacheTotal()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  return m_BytesPerSec ? (float)m_BufferLen / (float)m_BytesPerSec : 0.0f;
 | 
	
		
			
				|  |  | -+  float audioplus_buffer = m_SampleRate ? 0.0f : 32.0f * 512.0f / m_SampleRate;
 | 
	
		
			
				|  |  | -+  float input_buffer = (float)m_omx_decoder.GetInputBufferSize() / (float)m_InputBytesPerSec;
 | 
	
		
			
				|  |  | -+  return AUDIO_BUFFER_SECONDS + input_buffer + audioplus_buffer;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - //***********************************************************************************************
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h
 | 
	
		
			
				|  |  | -index 804bd2a..b0264d8 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudio.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudio.h
 | 
	
		
			
				|  |  | -@@ -66,7 +66,7 @@ class COMXAudio
 | 
	
		
			
				|  |  | -   ~COMXAudio();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   unsigned int AddPackets(const void* data, unsigned int len);
 | 
	
		
			
				|  |  | --  unsigned int AddPackets(const void* data, unsigned int len, double dts, double pts);
 | 
	
		
			
				|  |  | -+  unsigned int AddPackets(const void* data, unsigned int len, double dts, double pts, unsigned int frame_size);
 | 
	
		
			
				|  |  | -   unsigned int GetSpace();
 | 
	
		
			
				|  |  | -   bool Deinitialize();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -114,6 +114,7 @@ class COMXAudio
 | 
	
		
			
				|  |  | -   bool          m_Passthrough;
 | 
	
		
			
				|  |  | -   bool          m_HWDecode;
 | 
	
		
			
				|  |  | -   unsigned int  m_BytesPerSec;
 | 
	
		
			
				|  |  | -+  unsigned int  m_InputBytesPerSec;
 | 
	
		
			
				|  |  | -   unsigned int  m_BufferLen;
 | 
	
		
			
				|  |  | -   unsigned int  m_ChunkLen;
 | 
	
		
			
				|  |  | -   unsigned int  m_InputChannels;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -index 5503a0e..557e847 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -@@ -26,10 +26,15 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Utils/AEUtil.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+// the size of the audio_render output port buffers
 | 
	
		
			
				|  |  | -+#define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
 | 
	
		
			
				|  |  | -+static const char rounded_up_channels_shift[] = {0,0,1,2,2,3,3,3,3};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - COMXAudioCodecOMX::COMXAudioCodecOMX()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_pBufferOutput = NULL;
 | 
	
		
			
				|  |  | -   m_iBufferOutputAlloced = 0;
 | 
	
		
			
				|  |  | -+  m_iBufferOutputUsed = 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_pCodecContext = NULL;
 | 
	
		
			
				|  |  | -   m_pConvert = NULL;
 | 
	
		
			
				|  |  | -@@ -37,7 +42,10 @@ COMXAudioCodecOMX::COMXAudioCodecOMX()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_channels = 0;
 | 
	
		
			
				|  |  | -   m_pFrame1 = NULL;
 | 
	
		
			
				|  |  | -+  m_frameSize = 0;
 | 
	
		
			
				|  |  | -   m_bGotFrame = false;
 | 
	
		
			
				|  |  | -+  m_bNoConcatenate = false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   m_iSampleFormat = AV_SAMPLE_FMT_NONE;
 | 
	
		
			
				|  |  | -   m_desiredSampleFormat = AV_SAMPLE_FMT_NONE;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -@@ -47,6 +55,7 @@ COMXAudioCodecOMX::~COMXAudioCodecOMX()
 | 
	
		
			
				|  |  | -   m_dllAvUtil.av_free(m_pBufferOutput);
 | 
	
		
			
				|  |  | -   m_pBufferOutput = NULL;
 | 
	
		
			
				|  |  | -   m_iBufferOutputAlloced = 0;
 | 
	
		
			
				|  |  | -+  m_iBufferOutputUsed = 0;
 | 
	
		
			
				|  |  | -   Dispose();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -83,6 +92,10 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints)
 | 
	
		
			
				|  |  | -   m_pCodecContext->bit_rate = hints.bitrate;
 | 
	
		
			
				|  |  | -   m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  // vorbis has variable sized planar output, so skip concatenation
 | 
	
		
			
				|  |  | -+  if (hints.codec == AV_CODEC_ID_VORBIS)
 | 
	
		
			
				|  |  | -+    m_bNoConcatenate = true;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   if(m_pCodecContext->bits_per_coded_sample == 0)
 | 
	
		
			
				|  |  | -     m_pCodecContext->bits_per_coded_sample = 16;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -132,7 +145,7 @@ void COMXAudioCodecOMX::Dispose()
 | 
	
		
			
				|  |  | -   m_bGotFrame = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --int COMXAudioCodecOMX::Decode(BYTE* pData, int iSize)
 | 
	
		
			
				|  |  | -+int COMXAudioCodecOMX::Decode(BYTE* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   int iBytesUsed, got_frame;
 | 
	
		
			
				|  |  | -   if (!m_pCodecContext) return -1;
 | 
	
		
			
				|  |  | -@@ -167,10 +180,15 @@ int COMXAudioCodecOMX::Decode(BYTE* pData, int iSize)
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_bGotFrame = true;
 | 
	
		
			
				|  |  | -+  if (!m_iBufferOutputUsed)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_dts = dts;
 | 
	
		
			
				|  |  | -+    m_pts = pts;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   return iBytesUsed;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --int COMXAudioCodecOMX::GetData(BYTE** dst)
 | 
	
		
			
				|  |  | -+int COMXAudioCodecOMX::GetData(BYTE** dst, double &dts, double &pts)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (!m_bGotFrame)
 | 
	
		
			
				|  |  | -     return 0;
 | 
	
		
			
				|  |  | -@@ -179,13 +197,11 @@ int COMXAudioCodecOMX::GetData(BYTE** dst)
 | 
	
		
			
				|  |  | -   int inputSize = m_dllAvUtil.av_samples_get_buffer_size(&inLineSize, m_pCodecContext->channels, m_pFrame1->nb_samples, m_pCodecContext->sample_fmt, 0);
 | 
	
		
			
				|  |  | -   /* output audio will be packed */
 | 
	
		
			
				|  |  | -   int outputSize = m_dllAvUtil.av_samples_get_buffer_size(&outLineSize, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1);
 | 
	
		
			
				|  |  | --  bool cont = !m_pFrame1->data[1] || (m_pFrame1->data[1] == m_pFrame1->data[0] + inLineSize && inLineSize == outLineSize && inLineSize * m_pCodecContext->channels == inputSize);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (m_iBufferOutputAlloced < outputSize)
 | 
	
		
			
				|  |  | -+  if (m_iBufferOutputAlloced < m_iBufferOutputUsed + outputSize)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --     m_dllAvUtil.av_free(m_pBufferOutput);
 | 
	
		
			
				|  |  | --     m_pBufferOutput = (BYTE*)m_dllAvUtil.av_malloc(outputSize + FF_INPUT_BUFFER_PADDING_SIZE);
 | 
	
		
			
				|  |  | --     m_iBufferOutputAlloced = outputSize;
 | 
	
		
			
				|  |  | -+     m_pBufferOutput = (BYTE*)m_dllAvUtil.av_realloc(m_pBufferOutput, m_iBufferOutputUsed + outputSize + FF_INPUT_BUFFER_PADDING_SIZE);
 | 
	
		
			
				|  |  | -+     m_iBufferOutputAlloced = m_iBufferOutputUsed + outputSize;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   *dst = m_pBufferOutput;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -217,7 +233,7 @@ int COMXAudioCodecOMX::GetData(BYTE** dst)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     /* use unaligned flag to keep output packed */
 | 
	
		
			
				|  |  | -     uint8_t *out_planes[m_pCodecContext->channels];
 | 
	
		
			
				|  |  | --    if(m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
 | 
	
		
			
				|  |  | -+    if(m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput + m_iBufferOutputUsed, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
 | 
	
		
			
				|  |  | -        m_dllSwResample.swr_convert(m_pConvert, out_planes, m_pFrame1->nb_samples, (const uint8_t **)m_pFrame1->data, m_pFrame1->nb_samples) < 0)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       CLog::Log(LOGERROR, "COMXAudioCodecOMX::Decode - Unable to convert format %d to %d", (int)m_pCodecContext->sample_fmt, m_desiredSampleFormat);
 | 
	
		
			
				|  |  | -@@ -226,35 +242,45 @@ int COMXAudioCodecOMX::GetData(BYTE** dst)
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    /* if it is already contiguous, just return decoded frame */
 | 
	
		
			
				|  |  | --    if (cont)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      *dst = m_pFrame1->data[0];
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | -+    /* copy to a contiguous buffer */
 | 
	
		
			
				|  |  | -+    uint8_t *out_planes[m_pCodecContext->channels];
 | 
	
		
			
				|  |  | -+    if (m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput + m_iBufferOutputUsed, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
 | 
	
		
			
				|  |  | -+      m_dllAvUtil.av_samples_copy(out_planes, m_pFrame1->data, 0, 0, m_pFrame1->nb_samples, m_pCodecContext->channels, m_desiredSampleFormat) < 0 )
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      /* copy to a contiguous buffer */
 | 
	
		
			
				|  |  | --      uint8_t *out_planes[m_pCodecContext->channels];
 | 
	
		
			
				|  |  | --      if (m_dllAvUtil.av_samples_fill_arrays(out_planes, NULL, m_pBufferOutput, m_pCodecContext->channels, m_pFrame1->nb_samples, m_desiredSampleFormat, 1) < 0 ||
 | 
	
		
			
				|  |  | --        m_dllAvUtil.av_samples_copy(out_planes, m_pFrame1->data, 0, 0, m_pFrame1->nb_samples, m_pCodecContext->channels, m_desiredSampleFormat) < 0 )
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        outputSize = 0;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | -+      outputSize = 0;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  int desired_size = AUDIO_DECODE_OUTPUT_BUFFER * (m_pCodecContext->channels * GetBitsPerSample()) >> (rounded_up_channels_shift[m_pCodecContext->channels] + 4);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (m_bFirstFrame)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "COMXAudioCodecOMX::GetData size=%d/%d line=%d/%d cont=%d buf=%p", inputSize, outputSize, inLineSize, outLineSize, cont, *dst);
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG, "COMXAudioCodecOMX::GetData size=%d/%d line=%d/%d buf=%p, desired=%d", inputSize, outputSize, inLineSize, outLineSize, *dst, desired_size);
 | 
	
		
			
				|  |  | -     m_bFirstFrame = false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  return outputSize;
 | 
	
		
			
				|  |  | -+  m_iBufferOutputUsed += outputSize;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (!m_bNoConcatenate && m_pCodecContext->sample_fmt == AV_SAMPLE_FMT_FLTP && m_frameSize && (int)m_frameSize != outputSize)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "COMXAudioCodecOMX::GetData Unexpected change of size (%d->%d)", m_frameSize, outputSize);
 | 
	
		
			
				|  |  | -+  m_frameSize = outputSize;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // if next buffer submitted won't fit then flush it out
 | 
	
		
			
				|  |  | -+  if (m_iBufferOutputUsed + outputSize > desired_size || m_bNoConcatenate)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+     int ret = m_iBufferOutputUsed;
 | 
	
		
			
				|  |  | -+     m_bGotFrame = false;
 | 
	
		
			
				|  |  | -+     m_iBufferOutputUsed = 0;
 | 
	
		
			
				|  |  | -+     dts = m_dts;
 | 
	
		
			
				|  |  | -+     pts = m_pts;
 | 
	
		
			
				|  |  | -+     return ret;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  return 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COMXAudioCodecOMX::Reset()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if (m_pCodecContext) m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
 | 
	
		
			
				|  |  | -   m_bGotFrame = false;
 | 
	
		
			
				|  |  | -+  m_iBufferOutputUsed = 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - int COMXAudioCodecOMX::GetChannels()
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
 | 
	
		
			
				|  |  | -index 343465c..66e5b4a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
 | 
	
		
			
				|  |  | -@@ -36,8 +36,8 @@ class COMXAudioCodecOMX
 | 
	
		
			
				|  |  | -   virtual ~COMXAudioCodecOMX();
 | 
	
		
			
				|  |  | -   bool Open(CDVDStreamInfo &hints);
 | 
	
		
			
				|  |  | -   void Dispose();
 | 
	
		
			
				|  |  | --  int Decode(BYTE* pData, int iSize);
 | 
	
		
			
				|  |  | --  int GetData(BYTE** dst);
 | 
	
		
			
				|  |  | -+  int Decode(BYTE* pData, int iSize, double dts, double pts);
 | 
	
		
			
				|  |  | -+  int GetData(BYTE** dst, double &dts, double &pts);
 | 
	
		
			
				|  |  | -   void Reset();
 | 
	
		
			
				|  |  | -   int GetChannels();
 | 
	
		
			
				|  |  | -   uint64_t GetChannelMap();
 | 
	
		
			
				|  |  | -@@ -45,6 +45,7 @@ class COMXAudioCodecOMX
 | 
	
		
			
				|  |  | -   int GetBitsPerSample();
 | 
	
		
			
				|  |  | -   static const char* GetName() { return "FFmpeg"; }
 | 
	
		
			
				|  |  | -   int GetBitRate();
 | 
	
		
			
				|  |  | -+  unsigned int GetFrameSize() { return m_frameSize; }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   AVCodecContext* m_pCodecContext;
 | 
	
		
			
				|  |  | -@@ -55,6 +56,7 @@ class COMXAudioCodecOMX
 | 
	
		
			
				|  |  | -   AVFrame* m_pFrame1;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   BYTE *m_pBufferOutput;
 | 
	
		
			
				|  |  | -+  int   m_iBufferOutputUsed;
 | 
	
		
			
				|  |  | -   int   m_iBufferOutputAlloced;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool m_bOpenedCodec;
 | 
	
		
			
				|  |  | -@@ -63,6 +65,9 @@ class COMXAudioCodecOMX
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool m_bFirstFrame;
 | 
	
		
			
				|  |  | -   bool m_bGotFrame;
 | 
	
		
			
				|  |  | -+  bool m_bNoConcatenate;
 | 
	
		
			
				|  |  | -+  unsigned int  m_frameSize;
 | 
	
		
			
				|  |  | -+  double m_dts, m_pts;
 | 
	
		
			
				|  |  | -   DllAvCodec m_dllAvCodec;
 | 
	
		
			
				|  |  | -   DllAvUtil m_dllAvUtil;
 | 
	
		
			
				|  |  | -   DllSwResample m_dllSwResample;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -index 8219015..a4c11777 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -@@ -227,9 +227,10 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(!OMX_IS_RAW(m_format.m_dataFormat) && !bDropPacket)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -+    double dts = pkt->dts, pts=pkt->pts;
 | 
	
		
			
				|  |  | -     while(!m_bStop && data_len > 0)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len);
 | 
	
		
			
				|  |  | -+      int len = m_pAudioCodec->Decode((BYTE *)data_dec, data_len, dts, pts);
 | 
	
		
			
				|  |  | -       if( (len < 0) || (len >  data_len) )
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -         m_pAudioCodec->Reset();
 | 
	
		
			
				|  |  | -@@ -240,7 +241,7 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
 | 
	
		
			
				|  |  | -       data_len -= len;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       uint8_t *decoded;
 | 
	
		
			
				|  |  | --      int decoded_size = m_pAudioCodec->GetData(&decoded);
 | 
	
		
			
				|  |  | -+      int decoded_size = m_pAudioCodec->GetData(&decoded, dts, pts);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       if(decoded_size <=0)
 | 
	
		
			
				|  |  | -         continue;
 | 
	
		
			
				|  |  | -@@ -274,7 +275,7 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
 | 
	
		
			
				|  |  | -           if(m_silence)
 | 
	
		
			
				|  |  | -             memset(decoded, 0x0, decoded_size);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --          ret = m_omxAudio.AddPackets(decoded, decoded_size, m_audioClock, m_audioClock);
 | 
	
		
			
				|  |  | -+          ret = m_omxAudio.AddPackets(decoded, decoded_size, dts, pts, m_pAudioCodec->GetFrameSize());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -           if(ret != decoded_size)
 | 
	
		
			
				|  |  | -           {
 | 
	
		
			
				|  |  | -@@ -312,7 +313,7 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
 | 
	
		
			
				|  |  | -         if(m_silence)
 | 
	
		
			
				|  |  | -           memset(pkt->pData, 0x0, pkt->iSize);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --        m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock);
 | 
	
		
			
				|  |  | -+        m_omxAudio.AddPackets(pkt->pData, pkt->iSize, m_audioClock, m_audioClock, 0);
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       m_audioStats.AddSampleBytes(pkt->iSize);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 10a9d6134a624bf59096831851ee12191f658da1 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 5 Mar 2014 22:10:01 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 53/94] [omxplayer] Use media for determing audio delay and
 | 
	
		
			
				|  |  | - cache time
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -I've also added caching to the call to OMXMediaTime as the GPU round trip is expensive when called too frequently
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudio.cpp | 33 ++++++++++++++-------
 | 
	
		
			
				|  |  | - xbmc/linux/OMXClock.cpp           | 62 +++++++++++++++++++++++++++------------
 | 
	
		
			
				|  |  | - xbmc/linux/OMXClock.h             |  2 ++
 | 
	
		
			
				|  |  | - 3 files changed, 68 insertions(+), 29 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -index e67dc94..3e64de0 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -@@ -1118,29 +1118,40 @@ void COMXAudio::UpdateAttenuation()
 | 
	
		
			
				|  |  | - //***********************************************************************************************
 | 
	
		
			
				|  |  | - unsigned int COMXAudio::GetSpace()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  int free = m_omx_decoder.GetInputBufferSpace();
 | 
	
		
			
				|  |  | --  return free;
 | 
	
		
			
				|  |  | -+  return m_omx_decoder.GetInputBufferSpace();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - float COMXAudio::GetDelay()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  unsigned int free = m_omx_decoder.GetInputBufferSize() - m_omx_decoder.GetInputBufferSpace();
 | 
	
		
			
				|  |  | --  return m_BytesPerSec ? (float)free / (float)m_BytesPerSec : 0.0f;
 | 
	
		
			
				|  |  | -+  CSingleLock lock (m_critSection);
 | 
	
		
			
				|  |  | -+  double stamp = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -+  double ret = 0.0;
 | 
	
		
			
				|  |  | -+  if (m_last_pts != DVD_NOPTS_VALUE && m_av_clock)
 | 
	
		
			
				|  |  | -+    stamp = m_av_clock->OMXMediaTime();
 | 
	
		
			
				|  |  | -+  // if possible the delay is current media time - time of last submitted packet
 | 
	
		
			
				|  |  | -+  if (stamp != DVD_NOPTS_VALUE)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    ret = (m_last_pts - stamp) * (1.0 / DVD_TIME_BASE);
 | 
	
		
			
				|  |  | -+    //CLog::Log(LOGINFO, "%s::%s - %.2f %.0f %.0f", CLASSNAME, __func__, ret, stamp, m_last_pts);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else // just measure the input fifo
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    unsigned int used = m_omx_decoder.GetInputBufferSize() - m_omx_decoder.GetInputBufferSpace();
 | 
	
		
			
				|  |  | -+    float ret = m_InputBytesPerSec ? (float)used / (float)m_InputBytesPerSec : 0.0f;
 | 
	
		
			
				|  |  | -+    //CLog::Log(LOGINFO, "%s::%s - %.2f %d, %d, %d", CLASSNAME, __func__, ret, used, m_omx_decoder.GetInputBufferSize(), m_omx_decoder.GetInputBufferSpace());
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - float COMXAudio::GetCacheTime()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  float fBufferLenFull = (float)m_BufferLen - (float)GetSpace();
 | 
	
		
			
				|  |  | --  if(fBufferLenFull < 0)
 | 
	
		
			
				|  |  | --    fBufferLenFull = 0;
 | 
	
		
			
				|  |  | --  float ret = m_BytesPerSec ? fBufferLenFull / (float)m_BytesPerSec : 0.0f;
 | 
	
		
			
				|  |  | --  return ret;
 | 
	
		
			
				|  |  | -+  return GetDelay();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - float COMXAudio::GetCacheTotal()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  float audioplus_buffer = m_SampleRate ? 0.0f : 32.0f * 512.0f / m_SampleRate;
 | 
	
		
			
				|  |  | --  float input_buffer = (float)m_omx_decoder.GetInputBufferSize() / (float)m_InputBytesPerSec;
 | 
	
		
			
				|  |  | -+  float audioplus_buffer = m_SampleRate ? 32.0f * 512.0f / m_SampleRate : 0.0f;
 | 
	
		
			
				|  |  | -+  float input_buffer = m_InputBytesPerSec ? (float)m_omx_decoder.GetInputBufferSize() / (float)m_InputBytesPerSec : 0;
 | 
	
		
			
				|  |  | -   return AUDIO_BUFFER_SECONDS + input_buffer + audioplus_buffer;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/OMXClock.cpp b/xbmc/linux/OMXClock.cpp
 | 
	
		
			
				|  |  | -index 241657b..bee7bac 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/OMXClock.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/OMXClock.cpp
 | 
	
		
			
				|  |  | -@@ -45,6 +45,8 @@ OMXClock::OMXClock()
 | 
	
		
			
				|  |  | -   m_eState = OMX_TIME_ClockStateStopped;
 | 
	
		
			
				|  |  | -   m_eClock = OMX_TIME_RefClockNone;
 | 
	
		
			
				|  |  | -   m_clock        = NULL;
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -+  m_last_media_time_read = 0.0f;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   pthread_mutex_init(&m_lock, NULL);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -@@ -113,6 +115,7 @@ bool OMXClock::OMXSetReferenceClock(bool has_audio, bool lock /* = true */)
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     m_eClock = refClock.eClock;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -142,6 +145,7 @@ void OMXClock::OMXDeinitialize()
 | 
	
		
			
				|  |  | -   m_omx_clock.Deinitialize();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_omx_speed = DVD_PLAYSPEED_NORMAL;
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool OMXClock::OMXStateExecute(bool lock /* = true */)
 | 
	
		
			
				|  |  | -@@ -169,6 +173,7 @@ bool OMXClock::OMXStateExecute(bool lock /* = true */)
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -186,6 +191,7 @@ void OMXClock::OMXStateIdle(bool lock /* = true */)
 | 
	
		
			
				|  |  | -   if(m_omx_clock.GetState() != OMX_StateIdle)
 | 
	
		
			
				|  |  | -     m_omx_clock.SetStateForComponent(OMX_StateIdle);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -@@ -222,6 +228,7 @@ bool  OMXClock::OMXStop(bool lock /* = true */)
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   m_eState = clock.eState;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -252,6 +259,7 @@ bool OMXClock::OMXStep(int steps /* = 1 */, bool lock /* = true */)
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -302,6 +310,7 @@ bool OMXClock::OMXReset(bool has_video, bool has_audio, bool lock /* = true */)
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -310,33 +319,45 @@ bool OMXClock::OMXReset(bool has_video, bool has_audio, bool lock /* = true */)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - double OMXClock::OMXMediaTime(bool lock /* = true */)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+  double pts = 0.0;
 | 
	
		
			
				|  |  | -   if(m_omx_clock.GetComponent() == NULL)
 | 
	
		
			
				|  |  | -     return 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if(lock)
 | 
	
		
			
				|  |  | --    Lock();
 | 
	
		
			
				|  |  | -+  double now = GetAbsoluteClock();
 | 
	
		
			
				|  |  | -+  if (now - m_last_media_time_read > DVD_MSEC_TO_TIME(100) || m_last_media_time == 0.0)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if(lock)
 | 
	
		
			
				|  |  | -+      Lock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --  double pts = 0;
 | 
	
		
			
				|  |  | -+    OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
 | 
	
		
			
				|  |  | --  OMX_INIT_STRUCTURE(timeStamp);
 | 
	
		
			
				|  |  | --  timeStamp.nPortIndex = m_omx_clock.GetInputPort();
 | 
	
		
			
				|  |  | -+    OMX_TIME_CONFIG_TIMESTAMPTYPE timeStamp;
 | 
	
		
			
				|  |  | -+    OMX_INIT_STRUCTURE(timeStamp);
 | 
	
		
			
				|  |  | -+    timeStamp.nPortIndex = m_omx_clock.GetInputPort();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentMediaTime, &timeStamp);
 | 
	
		
			
				|  |  | -+    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "OMXClock::MediaTime error getting OMX_IndexConfigTimeCurrentMediaTime\n");
 | 
	
		
			
				|  |  | -+      if(lock)
 | 
	
		
			
				|  |  | -+        UnLock();
 | 
	
		
			
				|  |  | -+      return 0;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    pts = FromOMXTime(timeStamp.nTimestamp);
 | 
	
		
			
				|  |  | -+    //CLog::Log(LOGINFO, "OMXClock::MediaTime %.2f (%.2f, %.2f)", pts, m_last_media_time, now - m_last_media_time_read);
 | 
	
		
			
				|  |  | -+    m_last_media_time = pts;
 | 
	
		
			
				|  |  | -+    m_last_media_time_read = now;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  omx_err = m_omx_clock.GetConfig(OMX_IndexConfigTimeCurrentMediaTime, &timeStamp);
 | 
	
		
			
				|  |  | --  if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "OMXClock::MediaTime error getting OMX_IndexConfigTimeCurrentMediaTime\n");
 | 
	
		
			
				|  |  | -     if(lock)
 | 
	
		
			
				|  |  | -       UnLock();
 | 
	
		
			
				|  |  | --    return 0;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  pts = FromOMXTime(timeStamp.nTimestamp);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if(lock)
 | 
	
		
			
				|  |  | --    UnLock();
 | 
	
		
			
				|  |  | --  
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    double speed = m_pause ? 0.0 : (double)m_omx_speed / DVD_PLAYSPEED_NORMAL;
 | 
	
		
			
				|  |  | -+    pts = m_last_media_time + (now - m_last_media_time_read) * speed;
 | 
	
		
			
				|  |  | -+    //CLog::Log(LOGINFO, "OMXClock::MediaTime cached %.2f (%.2f, %.2f)", pts, m_last_media_time, now - m_last_media_time_read);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   return pts;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -409,6 +430,7 @@ bool OMXClock::OMXMediaTime(double pts, bool lock /* = true*/)
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "OMXClock::OMXMediaTime set config %s = %.2f", index == OMX_IndexConfigTimeCurrentAudioReference ?
 | 
	
		
			
				|  |  | -        "OMX_IndexConfigTimeCurrentAudioReference":"OMX_IndexConfigTimeCurrentVideoReference", pts);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -428,6 +450,7 @@ bool OMXClock::OMXPause(bool lock /* = true */)
 | 
	
		
			
				|  |  | -     if (OMXSetSpeed(0, false, true))
 | 
	
		
			
				|  |  | -       m_pause = true;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -     if(lock)
 | 
	
		
			
				|  |  | -       UnLock();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -@@ -447,6 +470,7 @@ bool OMXClock::OMXResume(bool lock /* = true */)
 | 
	
		
			
				|  |  | -     if (OMXSetSpeed(m_omx_speed, false, true))
 | 
	
		
			
				|  |  | -       m_pause = false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -     if(lock)
 | 
	
		
			
				|  |  | -       UnLock();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -@@ -485,6 +509,7 @@ bool OMXClock::OMXSetSpeed(int speed, bool lock /* = true */, bool pause_resume
 | 
	
		
			
				|  |  | -   if (!pause_resume)
 | 
	
		
			
				|  |  | -     m_omx_speed = speed;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -521,6 +546,7 @@ bool OMXClock::HDMIClockSync(bool lock /* = true */)
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_last_media_time = 0.0f;
 | 
	
		
			
				|  |  | -   if(lock)
 | 
	
		
			
				|  |  | -     UnLock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/OMXClock.h b/xbmc/linux/OMXClock.h
 | 
	
		
			
				|  |  | -index d7d06fe..f83074a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/OMXClock.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/OMXClock.h
 | 
	
		
			
				|  |  | -@@ -58,6 +58,8 @@ class OMXClock
 | 
	
		
			
				|  |  | -   CDVDClock         *m_clock;
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -   COMXCoreComponent m_omx_clock;
 | 
	
		
			
				|  |  | -+  double            m_last_media_time;
 | 
	
		
			
				|  |  | -+  double            m_last_media_time_read;
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -   OMXClock();
 | 
	
		
			
				|  |  | -   ~OMXClock();
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 29c5c42b2f5be546c242bc8ef02dc06a8dd0fd17 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 3 Mar 2014 22:24:19 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 54/94] [omx] Skip the resize when not needed when decoding
 | 
	
		
			
				|  |  | - jpegs
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The decode to texture path almost always uses cached jpegs that are the correct size, so the resize is rarely needed.
 | 
	
		
			
				|  |  | -The re-enc path usually needs resizing, but may not where the source is small.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Skipping the resize stage saves a little time and memory on GPU and also saves some setup time.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXImage.cpp | 262 ++++++++++++++++++++++----------------
 | 
	
		
			
				|  |  | - 1 file changed, 152 insertions(+), 110 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXImage.cpp b/xbmc/cores/omxplayer/OMXImage.cpp
 | 
	
		
			
				|  |  | -index 4456fdb..262a004 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXImage.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXImage.cpp
 | 
	
		
			
				|  |  | -@@ -1477,9 +1477,22 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
 | 
	
		
			
				|  |  | -       return false;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    if (resize_width != port_def.format.image.nFrameWidth || resize_height != port_def.format.image.nFrameHeight || (orientation & 4))
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     // TODO: jpeg decoder can decimate by factors of 2
 | 
	
		
			
				|  |  | -     port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
 | 
	
		
			
				|  |  | --    port_def.format.image.nSliceHeight = 16;//(port_def.format.image.nFrameHeight+15) & ~15;
 | 
	
		
			
				|  |  | -+    if (m_omx_resize.IsInitialized())
 | 
	
		
			
				|  |  | -+      port_def.format.image.nSliceHeight = 16;
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+      port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     port_def.format.image.nStride = 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     m_omx_decoder.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -@@ -1489,38 +1502,35 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
 | 
	
		
			
				|  |  | -       return false;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    if(!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
 | 
	
		
			
				|  |  | -+    if (m_omx_resize.IsInitialized())
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    port_def.nPortIndex = m_omx_resize.GetInputPort();
 | 
	
		
			
				|  |  | -+      port_def.nPortIndex = m_omx_resize.GetInputPort();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | --    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+      m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    port_def.nPortIndex = m_omx_resize.GetOutputPort();
 | 
	
		
			
				|  |  | --    m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | --    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
 | 
	
		
			
				|  |  | --    port_def.format.image.nFrameWidth = resize_width;
 | 
	
		
			
				|  |  | --    port_def.format.image.nFrameHeight = resize_height;
 | 
	
		
			
				|  |  | --    port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
 | 
	
		
			
				|  |  | --    port_def.format.image.nStride = 0;
 | 
	
		
			
				|  |  | --    m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | --    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | -+      port_def.nPortIndex = m_omx_resize.GetOutputPort();
 | 
	
		
			
				|  |  | -+      m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
 | 
	
		
			
				|  |  | -+      port_def.format.image.nFrameWidth = resize_width;
 | 
	
		
			
				|  |  | -+      port_def.format.image.nFrameHeight = resize_height;
 | 
	
		
			
				|  |  | -+      port_def.format.image.nSliceHeight = (resize_height+15) & ~15;
 | 
	
		
			
				|  |  | -+      port_def.format.image.nStride = 0;
 | 
	
		
			
				|  |  | -+      m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if(!m_omx_encoder.Initialize("OMX.broadcom.image_encode", OMX_IndexParamImageInit))
 | 
	
		
			
				|  |  | -@@ -1621,31 +1631,44 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
 | 
	
		
			
				|  |  | -       return false;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_err = m_omx_tunnel_decode.Establish();
 | 
	
		
			
				|  |  | --    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    if (m_omx_resize.IsInitialized())
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+      m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    m_omx_tunnel_resize.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_tunnel_decode.Establish();
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    omx_err = m_omx_tunnel_resize.Establish();
 | 
	
		
			
				|  |  | --    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_resize.Establish\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+      m_omx_tunnel_resize.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | --    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_tunnel_resize.Establish();
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_resize.Establish\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetStateForComponent result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_encoder, m_omx_encoder.GetInputPort());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_tunnel_decode.Establish();
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -     omx_err = m_omx_encoder.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | -     if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -@@ -1662,24 +1685,27 @@ bool COMXImageReEnc::HandlePortSettingChange(unsigned int resize_width, unsigned
 | 
	
		
			
				|  |  | -     // a little surprising, make a note
 | 
	
		
			
				|  |  | -     CLog::Log(LOGDEBUG, "%s::%s m_omx_resize second port changed event\n", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -     m_omx_decoder.DisablePort(m_omx_decoder.GetOutputPort(), true);
 | 
	
		
			
				|  |  | --    m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
 | 
	
		
			
				|  |  | -+    if (m_omx_resize.IsInitialized())
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      m_omx_resize.DisablePort(m_omx_resize.GetInputPort(), true);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    OMX_PARAM_PORTDEFINITIONTYPE port_def;
 | 
	
		
			
				|  |  | --    OMX_INIT_STRUCTURE(port_def);
 | 
	
		
			
				|  |  | -+      OMX_PARAM_PORTDEFINITIONTYPE port_def;
 | 
	
		
			
				|  |  | -+      OMX_INIT_STRUCTURE(port_def);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    port_def.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | --    m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | --    port_def.nPortIndex = m_omx_resize.GetInputPort();
 | 
	
		
			
				|  |  | --    m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+      port_def.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | -+      m_omx_decoder.GetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+      port_def.nPortIndex = m_omx_resize.GetInputPort();
 | 
	
		
			
				|  |  | -+      m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
 | 
	
		
			
				|  |  | --    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --      return false;
 | 
	
		
			
				|  |  | -+      omx_err = m_omx_resize.WaitForEvent(OMX_EventPortSettingsChanged);
 | 
	
		
			
				|  |  | -+      if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "%s::%s m_omx_resize.WaitForEvent=%x\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     m_omx_decoder.EnablePort(m_omx_decoder.GetOutputPort(), true);
 | 
	
		
			
				|  |  | --    m_omx_resize.EnablePort(m_omx_resize.GetInputPort(), true);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -@@ -1918,42 +1944,45 @@ bool COMXTexture::HandlePortSettingChange(unsigned int resize_width, unsigned in
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "%s::%s m_omx_decoder.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
 | 
	
		
			
				|  |  | -+  if (resize_width != port_def.format.image.nFrameWidth || resize_height != port_def.format.image.nFrameHeight)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | -+    if (!m_omx_resize.Initialize("OMX.broadcom.resize", OMX_IndexParamImageInit))
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s error m_omx_resize.Initialize", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  port_def.nPortIndex = m_omx_resize.GetInputPort();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | --  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  if (m_omx_resize.IsInitialized())
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    port_def.nPortIndex = m_omx_resize.GetInputPort();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  port_def.nPortIndex = m_omx_resize.GetOutputPort();
 | 
	
		
			
				|  |  | --  omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | --  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
 | 
	
		
			
				|  |  | --  port_def.format.image.nFrameWidth = resize_width;
 | 
	
		
			
				|  |  | --  port_def.format.image.nFrameHeight = resize_height;
 | 
	
		
			
				|  |  | --  port_def.format.image.nSliceHeight = 16;
 | 
	
		
			
				|  |  | --  port_def.format.image.nStride = 0;
 | 
	
		
			
				|  |  | --  omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | --  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    port_def.nPortIndex = m_omx_resize.GetOutputPort();
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_resize.GetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.GetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    port_def.format.image.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
 | 
	
		
			
				|  |  | -+    port_def.format.image.nFrameWidth = resize_width;
 | 
	
		
			
				|  |  | -+    port_def.format.image.nFrameHeight = resize_height;
 | 
	
		
			
				|  |  | -+    port_def.format.image.nSliceHeight = 16;
 | 
	
		
			
				|  |  | -+    port_def.format.image.nStride = 0;
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_resize.SetParameter(OMX_IndexParamPortDefinition, &port_def);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_resize.SetParameter result(0x%x)\n", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   if (!m_omx_egl_render.Initialize("OMX.broadcom.egl_render", OMX_IndexParamVideoInit))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.Initialize", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -@@ -1983,30 +2012,43 @@ bool COMXTexture::HandlePortSettingChange(unsigned int resize_width, unsigned in
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.UseEGLImage (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+  if (m_omx_resize.IsInitialized())
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_resize, m_omx_resize.GetInputPort());
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_tunnel_decode.Establish();
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  omx_err = m_omx_tunnel_decode.Establish();
 | 
	
		
			
				|  |  | --  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+    m_omx_tunnel_egl.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_omx_tunnel_egl.Initialize(&m_omx_resize, m_omx_resize.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_tunnel_egl.Establish();
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_egl.Establish (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  omx_err = m_omx_tunnel_egl.Establish();
 | 
	
		
			
				|  |  | --  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_egl.Establish (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetParameter (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  omx_err = m_omx_resize.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | --  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s error m_omx_egl_render.GetParameter (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | -+    m_omx_tunnel_decode.Initialize(&m_omx_decoder, m_omx_decoder.GetOutputPort(), &m_omx_egl_render, m_omx_egl_render.GetInputPort());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_tunnel_decode.Establish();
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_tunnel_decode.Establish (%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   omx_err = m_omx_egl_render.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 1156d9abfac43de458d4ba66e5494c1d027e0f17 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 8 Mar 2014 15:36:06 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 55/94] [hifiberry] Hack: force it to be recognised as IEC958
 | 
	
		
			
				|  |  | - capable to enable passthrough options
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp | 4 ++++
 | 
	
		
			
				|  |  | - 1 file changed, 4 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
 | 
	
		
			
				|  |  | -index b48a4fc..d9897e5 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkALSA.cpp
 | 
	
		
			
				|  |  | -@@ -932,6 +932,10 @@ void CAESinkALSA::EnumerateDevice(AEDeviceInfoList &list, const std::string &dev
 | 
	
		
			
				|  |  | -     if (snd_card_get_name(cardNr, &cardName) == 0)
 | 
	
		
			
				|  |  | -       info.m_displayName = cardName;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+    // hack: hifiberry digi doesn't correctly report as iec958 device. Needs fixing in kernel driver
 | 
	
		
			
				|  |  | -+    if (info.m_displayName == "snd_rpi_hifiberry_digi")
 | 
	
		
			
				|  |  | -+      info.m_deviceType = AE_DEVTYPE_IEC958;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     if (info.m_deviceType == AE_DEVTYPE_HDMI && info.m_displayName.size() > 5 &&
 | 
	
		
			
				|  |  | -         info.m_displayName.substr(info.m_displayName.size()-5) == " HDMI")
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 03aa9ebf0993f06d24a34f8dd7d86a183ebd2dcd Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Tue, 11 Mar 2014 18:50:23 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 56/94] [dvdplayer] Use inexact seeking like omxplayer
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDPlayer.cpp | 11 +++++++++++
 | 
	
		
			
				|  |  | - 1 file changed, 11 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDPlayer.cpp b/xbmc/cores/dvdplayer/DVDPlayer.cpp
 | 
	
		
			
				|  |  | -index d607f55..1d4ba52 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDPlayer.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDPlayer.cpp
 | 
	
		
			
				|  |  | -@@ -1935,7 +1935,11 @@ void CDVDPlayer::CheckAutoSceneSkip()
 | 
	
		
			
				|  |  | -     /*
 | 
	
		
			
				|  |  | -      * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
 | 
	
		
			
				|  |  | -      */
 | 
	
		
			
				|  |  | -+#ifdef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -+    m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, true, true, true, false, true));
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -     m_messenger.Put(new CDVDMsgPlayerSeek((int)seek, true, false, true, false, true));
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -     /*
 | 
	
		
			
				|  |  | -      * Seek doesn't always work reliably. Last physical seek time is recorded to prevent looping
 | 
	
		
			
				|  |  | -      * if there was an error with seeking and it landed somewhere unexpected, perhaps back in the
 | 
	
		
			
				|  |  | -@@ -1953,7 +1957,11 @@ void CDVDPlayer::CheckAutoSceneSkip()
 | 
	
		
			
				|  |  | -     /*
 | 
	
		
			
				|  |  | -      * Seeking is NOT flushed so any content up to the demux point is retained when playing forwards.
 | 
	
		
			
				|  |  | -      */
 | 
	
		
			
				|  |  | -+#ifdef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -+    m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, false, true, false, true));
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -     m_messenger.Put(new CDVDMsgPlayerSeek(cut.end + 1, true, false, true, false, true));
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -     /*
 | 
	
		
			
				|  |  | -      * Each commercial break is only skipped once so poorly detected commercial breaks can be
 | 
	
		
			
				|  |  | -      * manually re-entered. Start and end are recorded to prevent looping and to allow seeking back
 | 
	
		
			
				|  |  | -@@ -3293,9 +3301,12 @@ bool CDVDPlayer::CloseTeletextStream(bool bWaitForBuffers)
 | 
	
		
			
				|  |  | - void CDVDPlayer::FlushBuffers(bool queued, double pts, bool accurate)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   double startpts;
 | 
	
		
			
				|  |  | -+#ifndef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -+  /* for now, ignore accurate flag as it discards keyframes and causes corrupt frames */
 | 
	
		
			
				|  |  | -   if(accurate)
 | 
	
		
			
				|  |  | -     startpts = pts;
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -     startpts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   /* call with demuxer pts */
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From d4487b87819003a44f59a607074a41108f644915 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 13 Mar 2014 16:08:46 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 57/94] [omxplayer] Make use of TrueHD fastpath when downmixing
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The TrueHD codec actually works in 3 stages. It decodes the downmixed stereo. It then decodes the differences required to produce 5.1.
 | 
	
		
			
				|  |  | -It then decodes the differences required to produce 7.1.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Many users end up downmixing this 7.1 stream back to 2.0.
 | 
	
		
			
				|  |  | -Much better to tell the codec we only need the 2.0 stream. It saves about 50% of the CPU required
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp | 12 ++++++++++++
 | 
	
		
			
				|  |  | - 1 file changed, 12 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -index 557e847..7f6ef6e 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -@@ -25,6 +25,8 @@
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Utils/AEUtil.h"
 | 
	
		
			
				|  |  | -+#include "settings/Settings.h"
 | 
	
		
			
				|  |  | -+#include "PCMRemap.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - // the size of the audio_render output port buffers
 | 
	
		
			
				|  |  | - #define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
 | 
	
		
			
				|  |  | -@@ -91,6 +93,16 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints)
 | 
	
		
			
				|  |  | -   m_pCodecContext->block_align = hints.blockalign;
 | 
	
		
			
				|  |  | -   m_pCodecContext->bit_rate = hints.bitrate;
 | 
	
		
			
				|  |  | -   m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
 | 
	
		
			
				|  |  | -+  enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
 | 
	
		
			
				|  |  | -+  if (hints.codec == AV_CODEC_ID_TRUEHD)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (layout == PCM_LAYOUT_2_0)
 | 
	
		
			
				|  |  | -+      m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_STEREO;
 | 
	
		
			
				|  |  | -+    else if (layout <= PCM_LAYOUT_5_1)
 | 
	
		
			
				|  |  | -+      m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_5POINT1;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  if (m_pCodecContext->request_channel_layout)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGNOTICE,"COMXAudioCodecOMX::Open() Requesting channel layout of %d", (unsigned)m_pCodecContext->request_channel_layout);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // vorbis has variable sized planar output, so skip concatenation
 | 
	
		
			
				|  |  | -   if (hints.codec == AV_CODEC_ID_VORBIS)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 8dedad4307cbca1416262af9e2ac2404c7490713 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 15 Mar 2014 19:38:38 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 58/94] [omxplayer] When in dual audio mode, make one output
 | 
	
		
			
				|  |  | - the slave
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -May help audio sync between the two outputs
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudio.cpp | 4 ++--
 | 
	
		
			
				|  |  | - 1 file changed, 2 insertions(+), 2 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -index 3e64de0..72e42ec 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -@@ -245,7 +245,7 @@ bool COMXAudio::PortSettingsChanged()
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     // By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
 | 
	
		
			
				|  |  | -     // This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
 | 
	
		
			
				|  |  | --    if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
 | 
	
		
			
				|  |  | -+    if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || (CSettings::Get().GetBool("audiooutput.dualaudio") && CSettings::Get().GetString("audiooutput.audiodevice") != "PI:Analogue"))
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       OMX_CONFIG_BOOLEANTYPE configBool;
 | 
	
		
			
				|  |  | -       OMX_INIT_STRUCTURE(configBool);
 | 
	
		
			
				|  |  | -@@ -271,7 +271,7 @@ bool COMXAudio::PortSettingsChanged()
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     // By default audio_render is the clock master, and if output samples don't fit the timestamps, it will speed up/slow down the clock.
 | 
	
		
			
				|  |  | -     // This tends to be better for maintaining audio sync and avoiding audio glitches, but can affect video/display sync
 | 
	
		
			
				|  |  | --    if(CSettings::Get().GetBool("videoplayer.usedisplayasclock"))
 | 
	
		
			
				|  |  | -+    if(CSettings::Get().GetBool("videoplayer.usedisplayasclock") || (CSettings::Get().GetBool("audiooutput.dualaudio") && CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue"))
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       OMX_CONFIG_BOOLEANTYPE configBool;
 | 
	
		
			
				|  |  | -       OMX_INIT_STRUCTURE(configBool);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 96842193cb39ac3625a1dcbdd67388141733a5ee Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 30 Dec 2013 12:02:14 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 59/94] [rbp] Hardware accelerated resampling
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This replaces the format conversion, up/down mixing and resampling code from ActiveAE with a GPU accelerated version.
 | 
	
		
			
				|  |  | -Should significantly reduce CPU when using paplayer or dvdplayer.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Requires updated firmware
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - .../Engines/ActiveAE/ActiveAEResample.cpp          |   5 +
 | 
	
		
			
				|  |  | - .../Engines/ActiveAE/ActiveAEResample.h            |   9 +
 | 
	
		
			
				|  |  | - .../Engines/ActiveAE/ActiveAEResamplePi.cpp        | 592 +++++++++++++++++++++
 | 
	
		
			
				|  |  | - .../Engines/ActiveAE/ActiveAEResamplePi.h          |  65 +++
 | 
	
		
			
				|  |  | - xbmc/cores/AudioEngine/Makefile.in                 |   1 +
 | 
	
		
			
				|  |  | - xbmc/linux/OMXCore.cpp                             |   4 +-
 | 
	
		
			
				|  |  | - 6 files changed, 674 insertions(+), 2 deletions(-)
 | 
	
		
			
				|  |  | - create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | - create mode 100644 xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
 | 
	
		
			
				|  |  | -index e131f16..94b69a0 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.cpp
 | 
	
		
			
				|  |  | -@@ -18,6 +18,10 @@
 | 
	
		
			
				|  |  | -  *
 | 
	
		
			
				|  |  | -  */
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#include "system.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#if !defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #include "ActiveAEResample.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - using namespace ActiveAE;
 | 
	
		
			
				|  |  | -@@ -344,3 +348,4 @@ int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layo
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   return m_dllAvUtil.av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel));
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
 | 
	
		
			
				|  |  | -index 1e0e342..6a8949b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResample.h
 | 
	
		
			
				|  |  | -@@ -21,11 +21,18 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "DllAvUtil.h"
 | 
	
		
			
				|  |  | - #include "DllSwResample.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "system.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Utils/AEChannelInfo.h"
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Utils/AEAudioFormat.h"
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Engines/ActiveAE/ActiveAEBuffer.h"
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Interfaces/AE.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#if defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | -+#include "ActiveAEResamplePi.h"
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - namespace ActiveAE
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -62,3 +69,5 @@ class CActiveAEResample
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..1d7b425
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -@@ -0,0 +1,592 @@
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ *      Copyright (C) 2010-2013 Team XBMC
 | 
	
		
			
				|  |  | -+ *      http://xbmc.org
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -+ *  any later version.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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 XBMC; see the file COPYING.  If not, see
 | 
	
		
			
				|  |  | -+ *  <http://www.gnu.org/licenses/>.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "system.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#if defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "ActiveAEResample.h"
 | 
	
		
			
				|  |  | -+#include "linux/RBP.h"
 | 
	
		
			
				|  |  | -+#include "cores/omxplayer/PCMRemap.h"
 | 
	
		
			
				|  |  | -+#include "settings/Settings.h"
 | 
	
		
			
				|  |  | -+#include "utils/log.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+//#define DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define CLASSNAME "CActiveAEResamplePi"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define BUFFERSIZE (32*1024*2*8)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+//#define BENCHMARKING
 | 
	
		
			
				|  |  | -+#ifdef BENCHMARKING
 | 
	
		
			
				|  |  | -+#define LOGTIMEINIT(f) \
 | 
	
		
			
				|  |  | -+  struct timespec now; \
 | 
	
		
			
				|  |  | -+  uint64_t  Start, End; \
 | 
	
		
			
				|  |  | -+  clock_gettime(CLOCK_MONOTONIC, &now); \
 | 
	
		
			
				|  |  | -+  Start = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \
 | 
	
		
			
				|  |  | -+  const char *_filename = f;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#define LOGTIME(n) \
 | 
	
		
			
				|  |  | -+  clock_gettime(CLOCK_MONOTONIC, &now); \
 | 
	
		
			
				|  |  | -+  End = ((int64_t)now.tv_sec * 1000000000L) + now.tv_nsec; \
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGNOTICE, "ActiveAE::%s %d - resample %s took %.0fms", __FUNCTION__, n, _filename, (End-Start)*1e-6); \
 | 
	
		
			
				|  |  | -+  Start=End;
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -+#define LOGTIMEINIT(f)
 | 
	
		
			
				|  |  | -+#define LOGTIME(n)
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+using namespace ActiveAE;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CActiveAEResample::CActiveAEResample()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  m_loaded = false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_dllAvUtil.Load() && m_dllSwResample.Load())
 | 
	
		
			
				|  |  | -+    m_loaded = true;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_Initialized = false;
 | 
	
		
			
				|  |  | -+  m_last_src_fmt = AV_SAMPLE_FMT_NONE;
 | 
	
		
			
				|  |  | -+  m_last_dst_fmt = AV_SAMPLE_FMT_NONE;
 | 
	
		
			
				|  |  | -+  m_last_src_channels = 0;
 | 
	
		
			
				|  |  | -+  m_last_dst_channels = 0;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CActiveAEResample::~CActiveAEResample()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  DeInit();
 | 
	
		
			
				|  |  | -+  m_dllAvUtil.Unload();
 | 
	
		
			
				|  |  | -+  m_dllSwResample.Unload();
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CActiveAEResample::DeInit()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s:%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  if (m_Initialized)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_omx_mixer.FlushAll();
 | 
	
		
			
				|  |  | -+    m_omx_mixer.Deinitialize();
 | 
	
		
			
				|  |  | -+    m_Initialized = false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  LOGTIMEINIT("x");
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d rate:%d->%d format:%d->%d bits:%d->%d norm:%d upmix:%d", CLASSNAME, __func__, remapLayout, src_channels, dst_channels, src_rate, dst_rate, src_fmt, dst_fmt, src_bits, dst_bits, normalize, upmix);
 | 
	
		
			
				|  |  | -+  if (!m_loaded)
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_dst_chan_layout = dst_chan_layout;
 | 
	
		
			
				|  |  | -+  m_dst_channels = dst_channels;
 | 
	
		
			
				|  |  | -+  m_dst_rate = dst_rate;
 | 
	
		
			
				|  |  | -+  m_dst_fmt = dst_fmt;
 | 
	
		
			
				|  |  | -+  m_dst_bits = dst_bits ? dst_bits : 8;
 | 
	
		
			
				|  |  | -+  m_src_chan_layout = src_chan_layout;
 | 
	
		
			
				|  |  | -+  m_src_channels = src_channels;
 | 
	
		
			
				|  |  | -+  m_src_rate = src_rate;
 | 
	
		
			
				|  |  | -+  m_src_fmt = src_fmt;
 | 
	
		
			
				|  |  | -+  m_src_bits = src_bits ? src_bits : 8;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_dst_chan_layout == 0)
 | 
	
		
			
				|  |  | -+    m_dst_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_dst_channels);
 | 
	
		
			
				|  |  | -+  if (m_src_chan_layout == 0)
 | 
	
		
			
				|  |  | -+    m_src_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_src_channels);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 mix;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(mix);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  assert(sizeof(mix.coeff)/sizeof(mix.coeff[0]) == 64);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(1);
 | 
	
		
			
				|  |  | -+// this code is just uses ffmpeg to produce the 8x8 mixing matrix
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  // dummy sample rate and format, as we only care about channel mapping
 | 
	
		
			
				|  |  | -+  SwrContext *m_pContext = m_dllSwResample.swr_alloc_set_opts(NULL, m_dst_chan_layout, AV_SAMPLE_FMT_FLT, 48000,
 | 
	
		
			
				|  |  | -+                                                        m_src_chan_layout, AV_SAMPLE_FMT_FLT, 48000, 0, NULL);
 | 
	
		
			
				|  |  | -+  if (!m_pContext)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "CActiveAEResample::Init - create context failed");
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  // tell resampler to clamp float values
 | 
	
		
			
				|  |  | -+  // not required for sink stage (remapLayout == true)
 | 
	
		
			
				|  |  | -+  if (!remapLayout && normalize)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_dllAvUtil.av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (remapLayout)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    // one-to-one mapping of channels
 | 
	
		
			
				|  |  | -+    // remapLayout is the layout of the sink, if the channel is in our src layout
 | 
	
		
			
				|  |  | -+    // the channel is mapped by setting coef 1.0
 | 
	
		
			
				|  |  | -+    double m_rematrix[AE_CH_MAX][AE_CH_MAX];
 | 
	
		
			
				|  |  | -+    memset(m_rematrix, 0, sizeof(m_rematrix));
 | 
	
		
			
				|  |  | -+    m_dst_chan_layout = 0;
 | 
	
		
			
				|  |  | -+    for (unsigned int out=0; out<remapLayout->Count(); out++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      m_dst_chan_layout += (uint64_t) (1 << out);
 | 
	
		
			
				|  |  | -+      int idx = GetAVChannelIndex((*remapLayout)[out], m_src_chan_layout);
 | 
	
		
			
				|  |  | -+      if (idx >= 0)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        m_rematrix[out][idx] = 1.0;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    m_dllAvUtil.av_opt_set_int(m_pContext, "out_channel_count", m_dst_channels, 0);
 | 
	
		
			
				|  |  | -+    m_dllAvUtil.av_opt_set_int(m_pContext, "out_channel_layout", m_dst_chan_layout, 0);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (m_dllSwResample.swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed");
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  // stereo upmix
 | 
	
		
			
				|  |  | -+  else if (upmix && m_src_channels == 2 && m_dst_channels > 2)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    double m_rematrix[AE_CH_MAX][AE_CH_MAX];
 | 
	
		
			
				|  |  | -+    memset(m_rematrix, 0, sizeof(m_rematrix));
 | 
	
		
			
				|  |  | -+    for (int out=0; out<m_dst_channels; out++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      uint64_t out_chan = m_dllAvUtil.av_channel_layout_extract_channel(m_dst_chan_layout, out);
 | 
	
		
			
				|  |  | -+      switch(out_chan)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        case AV_CH_FRONT_LEFT:
 | 
	
		
			
				|  |  | -+        case AV_CH_BACK_LEFT:
 | 
	
		
			
				|  |  | -+        case AV_CH_SIDE_LEFT:
 | 
	
		
			
				|  |  | -+          m_rematrix[out][0] = 1.0;
 | 
	
		
			
				|  |  | -+          break;
 | 
	
		
			
				|  |  | -+        case AV_CH_FRONT_RIGHT:
 | 
	
		
			
				|  |  | -+        case AV_CH_BACK_RIGHT:
 | 
	
		
			
				|  |  | -+        case AV_CH_SIDE_RIGHT:
 | 
	
		
			
				|  |  | -+          m_rematrix[out][1] = 1.0;
 | 
	
		
			
				|  |  | -+          break;
 | 
	
		
			
				|  |  | -+        case AV_CH_FRONT_CENTER:
 | 
	
		
			
				|  |  | -+          m_rematrix[out][0] = 0.5;
 | 
	
		
			
				|  |  | -+          m_rematrix[out][1] = 0.5;
 | 
	
		
			
				|  |  | -+          break;
 | 
	
		
			
				|  |  | -+        case AV_CH_LOW_FREQUENCY:
 | 
	
		
			
				|  |  | -+          m_rematrix[out][0] = 0.5;
 | 
	
		
			
				|  |  | -+          m_rematrix[out][1] = 0.5;
 | 
	
		
			
				|  |  | -+          break;
 | 
	
		
			
				|  |  | -+        default:
 | 
	
		
			
				|  |  | -+          break;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (m_dllSwResample.swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "CActiveAEResample::Init - setting channel matrix failed");
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_dllSwResample.swr_init(m_pContext) < 0)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "CActiveAEResample::Init - init resampler failed");
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  const int samples = 8;
 | 
	
		
			
				|  |  | -+  uint8_t *output, *input;
 | 
	
		
			
				|  |  | -+  av_samples_alloc(&output, NULL, m_dst_channels, samples, AV_SAMPLE_FMT_FLT, 1);
 | 
	
		
			
				|  |  | -+  av_samples_alloc(&input , NULL, m_src_channels, samples, AV_SAMPLE_FMT_FLT, 1);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // Produce "identity" samples
 | 
	
		
			
				|  |  | -+  float *f = (float *)input;
 | 
	
		
			
				|  |  | -+  for (int j=0; j < samples; j++)
 | 
	
		
			
				|  |  | -+    for (int i=0; i < m_src_channels; i++)
 | 
	
		
			
				|  |  | -+      *f++ = i == j ? 1.0f : 0.0f;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  int ret = m_dllSwResample.swr_convert(m_pContext, &output, samples, (const uint8_t **)&input, samples);
 | 
	
		
			
				|  |  | -+  if (ret < 0)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "CActiveAEResample::Resample - resample failed");
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  f = (float *)output;
 | 
	
		
			
				|  |  | -+  for (int j=0; j < samples; j++)
 | 
	
		
			
				|  |  | -+    for (int i=0; i < m_dst_channels; i++)
 | 
	
		
			
				|  |  | -+      mix.coeff[8*i+j] = *f++ * (1<<16);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  for (int j=0; j < 8; j++)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    char s[128] = {}, *t=s;
 | 
	
		
			
				|  |  | -+    for (int i=0; i < 8; i++)
 | 
	
		
			
				|  |  | -+      t += sprintf(t, "% 6.2f ", mix.coeff[j*8+i] * (1.0/0x10000));
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGINFO, "%s::%s  %s", CLASSNAME, __func__, s);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  av_freep(&input);
 | 
	
		
			
				|  |  | -+  av_freep(&output);
 | 
	
		
			
				|  |  | -+  m_dllSwResample.swr_free(&m_pContext);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+  LOGTIME(2);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // This may be called before Application calls g_RBP.Initialise, so call it here too
 | 
	
		
			
				|  |  | -+  g_RBP.Initialize();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (!m_omx_mixer.Initialize("OMX.broadcom.audio_mixer", OMX_IndexParamAudioInit))
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - m_omx_mixer.Initialize omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(3);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(m_pcm_input);
 | 
	
		
			
				|  |  | -+  m_pcm_input.nPortIndex            = m_omx_mixer.GetInputPort();
 | 
	
		
			
				|  |  | -+  m_pcm_input.eNumData              = OMX_NumericalDataSigned;
 | 
	
		
			
				|  |  | -+  m_pcm_input.eEndian               = OMX_EndianLittle;
 | 
	
		
			
				|  |  | -+  m_pcm_input.bInterleaved          = OMX_TRUE;
 | 
	
		
			
				|  |  | -+  m_pcm_input.nBitPerSample         = m_src_bits;
 | 
	
		
			
				|  |  | -+  m_pcm_input.ePCMMode              = m_src_fmt == AV_SAMPLE_FMT_FLT ? (OMX_AUDIO_PCMMODETYPE)0x8000 : OMX_AUDIO_PCMModeLinear;
 | 
	
		
			
				|  |  | -+  m_pcm_input.nChannels             = src_channels;
 | 
	
		
			
				|  |  | -+  m_pcm_input.nSamplingRate         = src_rate;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_input);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer in SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(m_pcm_output);
 | 
	
		
			
				|  |  | -+  m_pcm_output.nPortIndex            = m_omx_mixer.GetOutputPort();
 | 
	
		
			
				|  |  | -+  m_pcm_output.eNumData              = OMX_NumericalDataSigned;
 | 
	
		
			
				|  |  | -+  m_pcm_output.eEndian               = OMX_EndianLittle;
 | 
	
		
			
				|  |  | -+  m_pcm_output.bInterleaved          = OMX_TRUE;
 | 
	
		
			
				|  |  | -+  m_pcm_output.nBitPerSample         = m_dst_bits;
 | 
	
		
			
				|  |  | -+  m_pcm_output.ePCMMode              = m_dst_fmt == AV_SAMPLE_FMT_FLT ? (OMX_AUDIO_PCMMODETYPE)0x8000 : OMX_AUDIO_PCMModeLinear;
 | 
	
		
			
				|  |  | -+  m_pcm_output.nChannels             = dst_channels;
 | 
	
		
			
				|  |  | -+  m_pcm_output.nSamplingRate         = dst_rate;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.SetParameter(OMX_IndexParamAudioPcm, &m_pcm_output);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - error m_omx_mixer out SetParameter omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(4);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  mix.nPortIndex = m_omx_mixer.GetInputPort();
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.SetConfig(OMX_IndexConfigBrcmAudioDownmixCoefficients8x8, &mix);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - error setting mixer OMX_IndexConfigBrcmAudioDownmixCoefficients, error 0x%08x\n",
 | 
	
		
			
				|  |  | -+              CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // set up the number/size of buffers for decoder input
 | 
	
		
			
				|  |  | -+  OMX_PARAM_PORTDEFINITIONTYPE port_param;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(port_param);
 | 
	
		
			
				|  |  | -+  port_param.nPortIndex = m_omx_mixer.GetInputPort();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1);
 | 
	
		
			
				|  |  | -+  port_param.nBufferSize = BUFFERSIZE;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(5);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.AllocInputBuffers();
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(6);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // set up the number/size of buffers for decoder output
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(port_param);
 | 
	
		
			
				|  |  | -+  port_param.nPortIndex = m_omx_mixer.GetOutputPort();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.GetParameter(OMX_IndexParamPortDefinition, &port_param);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)1);
 | 
	
		
			
				|  |  | -+  port_param.nBufferSize = BUFFERSIZE;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.SetParameter(OMX_IndexParamPortDefinition, &port_param);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s - error set OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(7);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.AllocOutputBuffers();
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s - Error alloc buffers 0x%08x", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(8);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_mixer.SetStateForComponent(OMX_StateExecuting);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s - m_omx_mixer OMX_StateExecuting omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  LOGTIME(9);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_Initialized = true;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int CActiveAEResample::Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s samples:%d->%d (%.2f)", CLASSNAME, __func__, src_samples, dst_samples, ratio);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  if (!m_Initialized)
 | 
	
		
			
				|  |  | -+    return 0;
 | 
	
		
			
				|  |  | -+  OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  const int s_pitch = m_pcm_input.nChannels * m_src_bits >> 3;
 | 
	
		
			
				|  |  | -+  const int d_pitch = m_pcm_output.nChannels * m_dst_bits >> 3;
 | 
	
		
			
				|  |  | -+  int sent = 0;
 | 
	
		
			
				|  |  | -+  int received = 0;
 | 
	
		
			
				|  |  | -+  while (sent < src_samples)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
 | 
	
		
			
				|  |  | -+    OMX_BUFFERHEADERTYPE *m_encoded_buffer = NULL;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_buffer = m_omx_mixer.GetInputBuffer(1000);
 | 
	
		
			
				|  |  | -+    if (omx_buffer == NULL)
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    const int max_src_samples = BUFFERSIZE / s_pitch;
 | 
	
		
			
				|  |  | -+    const int max_dst_samples = (long long)(BUFFERSIZE/d_pitch) * m_src_rate / (m_dst_rate + m_src_rate-1);
 | 
	
		
			
				|  |  | -+    int send = std::min(std::min(max_dst_samples, max_src_samples), src_samples - sent);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_buffer->nOffset = 0;
 | 
	
		
			
				|  |  | -+    omx_buffer->nFlags = OMX_BUFFERFLAG_EOS;
 | 
	
		
			
				|  |  | -+    omx_buffer->nFilledLen = send * s_pitch;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    assert(omx_buffer->nFilledLen > 0 && omx_buffer->nFilledLen <= omx_buffer->nAllocLen);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (omx_buffer->nFilledLen)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      memcpy(omx_buffer->pBuffer, src_buffer[0] + sent * s_pitch, omx_buffer->nFilledLen);
 | 
	
		
			
				|  |  | -+      sent += send;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_mixer.EmptyThisBuffer(omx_buffer);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s OMX_EmptyThisBuffer() failed with result(0x%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    m_encoded_buffer = m_omx_mixer.GetOutputBuffer();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (!m_encoded_buffer)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s no output buffer", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_mixer.FillThisBuffer(m_encoded_buffer);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_mixer.WaitForOutputDone(1000);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_mixer.WaitForOutputDone result(0x%x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    assert(m_encoded_buffer->nFilledLen > 0 && m_encoded_buffer->nFilledLen <= m_encoded_buffer->nAllocLen);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (m_omx_mixer.BadState())
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "%s::%s m_omx_mixer.BadState", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (m_encoded_buffer->nFilledLen)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      memcpy(dst_buffer[0] + received * d_pitch, m_encoded_buffer->pBuffer, m_encoded_buffer->nFilledLen);
 | 
	
		
			
				|  |  | -+      received += m_encoded_buffer->nFilledLen / d_pitch;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s format:%d->%d rate:%d->%d chan:%d->%d samples %d->%d (%f) %d =%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -+    (int)m_src_fmt, (int)m_dst_fmt, m_src_rate, m_dst_rate, m_src_channels, m_dst_channels, src_samples, dst_samples, ratio, m_Initialized, received);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return received;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int64_t CActiveAEResample::GetDelay(int64_t base)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  int ret = 0;
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int CActiveAEResample::GetBufferedSamples()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  int ret = 0;
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int CActiveAEResample::CalcDstSampleCount(int src_samples, int dst_rate, int src_rate)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  int ret = ((long long)src_samples * dst_rate + src_rate-1) / src_rate;
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int CActiveAEResample::GetSrcBufferSize(int samples)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  int ret = 0;
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int CActiveAEResample::GetDstBufferSize(int samples)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  int ret = CalcDstSampleCount(samples, m_dst_rate, m_src_rate);
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s = %d", CLASSNAME, __func__, ret);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return ret;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+uint64_t CActiveAEResample::GetAVChannelLayout(CAEChannelInfo &info)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  uint64_t channelLayout = 0;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FL))   channelLayout |= AV_CH_FRONT_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FR))   channelLayout |= AV_CH_FRONT_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FC))   channelLayout |= AV_CH_FRONT_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_LFE))  channelLayout |= AV_CH_LOW_FREQUENCY;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_BL))   channelLayout |= AV_CH_BACK_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_BR))   channelLayout |= AV_CH_BACK_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_BC))   channelLayout |= AV_CH_BACK_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_SL))   channelLayout |= AV_CH_SIDE_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_SR))   channelLayout |= AV_CH_SIDE_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TC))   channelLayout |= AV_CH_TOP_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TFL))  channelLayout |= AV_CH_TOP_FRONT_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TFC))  channelLayout |= AV_CH_TOP_FRONT_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TFR))  channelLayout |= AV_CH_TOP_FRONT_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TBL))   channelLayout |= AV_CH_TOP_BACK_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TBC))   channelLayout |= AV_CH_TOP_BACK_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TBR))   channelLayout |= AV_CH_TOP_BACK_RIGHT;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return channelLayout;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+AVSampleFormat CActiveAEResample::GetAVSampleFormat(AEDataFormat format)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  if      (format == AE_FMT_U8)     return AV_SAMPLE_FMT_U8;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_S16NE)  return AV_SAMPLE_FMT_S16;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_S32NE)  return AV_SAMPLE_FMT_S32;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_S24NE4) return AV_SAMPLE_FMT_S32;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_FLOAT)  return AV_SAMPLE_FMT_FLT;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_DOUBLE) return AV_SAMPLE_FMT_DBL;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_U8P)     return AV_SAMPLE_FMT_U8P;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_S16NEP)  return AV_SAMPLE_FMT_S16P;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_S32NEP)  return AV_SAMPLE_FMT_S32P;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_S24NE4P) return AV_SAMPLE_FMT_S32P;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_FLOATP)  return AV_SAMPLE_FMT_FLTP;
 | 
	
		
			
				|  |  | -+  else if (format == AE_FMT_DOUBLEP) return AV_SAMPLE_FMT_DBLP;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return AV_SAMPLE_FMT_FLT;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+AEDataFormat CActiveAEResample::GetAESampleFormat(AVSampleFormat format, int bits)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  if      (format == AV_SAMPLE_FMT_U8)   return AE_FMT_U8;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_S16)  return AE_FMT_S16NE;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_S32 && bits == 32)  return AE_FMT_S32NE;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_S32 && bits == 24)  return AE_FMT_S24NE4;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_FLT)  return AE_FMT_FLOAT;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_DBL)  return AE_FMT_DOUBLE;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_U8P)   return AE_FMT_U8P;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_S16P)  return AE_FMT_S16NEP;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_S32P && bits == 32)  return AE_FMT_S32NEP;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_S32P && bits == 24)  return AE_FMT_S24NE4P;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_FLTP)  return AE_FMT_FLOATP;
 | 
	
		
			
				|  |  | -+  else if (format == AV_SAMPLE_FMT_DBLP)  return AE_FMT_DOUBLEP;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGERROR, "CActiveAEResample::GetAESampleFormat - format not supported");
 | 
	
		
			
				|  |  | -+  return AE_FMT_INVALID;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+uint64_t CActiveAEResample::GetAVChannel(enum AEChannel aechannel)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  switch (aechannel)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+  case AE_CH_FL:   return AV_CH_FRONT_LEFT;
 | 
	
		
			
				|  |  | -+  case AE_CH_FR:   return AV_CH_FRONT_RIGHT;
 | 
	
		
			
				|  |  | -+  case AE_CH_FC:   return AV_CH_FRONT_CENTER;
 | 
	
		
			
				|  |  | -+  case AE_CH_LFE:  return AV_CH_LOW_FREQUENCY;
 | 
	
		
			
				|  |  | -+  case AE_CH_BL:   return AV_CH_BACK_LEFT;
 | 
	
		
			
				|  |  | -+  case AE_CH_BR:   return AV_CH_BACK_RIGHT;
 | 
	
		
			
				|  |  | -+  case AE_CH_FLOC: return AV_CH_FRONT_LEFT_OF_CENTER;
 | 
	
		
			
				|  |  | -+  case AE_CH_FROC: return AV_CH_FRONT_RIGHT_OF_CENTER;
 | 
	
		
			
				|  |  | -+  case AE_CH_BC:   return AV_CH_BACK_CENTER;
 | 
	
		
			
				|  |  | -+  case AE_CH_SL:   return AV_CH_SIDE_LEFT;
 | 
	
		
			
				|  |  | -+  case AE_CH_SR:   return AV_CH_SIDE_RIGHT;
 | 
	
		
			
				|  |  | -+  case AE_CH_TC:   return AV_CH_TOP_CENTER;
 | 
	
		
			
				|  |  | -+  case AE_CH_TFL:  return AV_CH_TOP_FRONT_LEFT;
 | 
	
		
			
				|  |  | -+  case AE_CH_TFC:  return AV_CH_TOP_FRONT_CENTER;
 | 
	
		
			
				|  |  | -+  case AE_CH_TFR:  return AV_CH_TOP_FRONT_RIGHT;
 | 
	
		
			
				|  |  | -+  case AE_CH_TBL:  return AV_CH_TOP_BACK_LEFT;
 | 
	
		
			
				|  |  | -+  case AE_CH_TBC:  return AV_CH_TOP_BACK_CENTER;
 | 
	
		
			
				|  |  | -+  case AE_CH_TBR:  return AV_CH_TOP_BACK_RIGHT;
 | 
	
		
			
				|  |  | -+  default:
 | 
	
		
			
				|  |  | -+    return 0;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int CActiveAEResample::GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  return m_dllAvUtil.av_get_channel_layout_channel_index(layout, GetAVChannel(aechannel));
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
 | 
	
		
			
				|  |  | -new file mode 100644
 | 
	
		
			
				|  |  | -index 0000000..8371c33
 | 
	
		
			
				|  |  | ---- /dev/null
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.h
 | 
	
		
			
				|  |  | -@@ -0,0 +1,65 @@
 | 
	
		
			
				|  |  | -+#pragma once
 | 
	
		
			
				|  |  | -+/*
 | 
	
		
			
				|  |  | -+ *      Copyright (C) 2010-2013 Team XBMC
 | 
	
		
			
				|  |  | -+ *      http://xbmc.org
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -+ *  any later version.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ *  This Program 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 XBMC; see the file COPYING.  If not, see
 | 
	
		
			
				|  |  | -+ *  <http://www.gnu.org/licenses/>.
 | 
	
		
			
				|  |  | -+ *
 | 
	
		
			
				|  |  | -+ */
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+#include "linux/OMXCore.h"
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+namespace ActiveAE
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+class CActiveAEResample
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+public:
 | 
	
		
			
				|  |  | -+  CActiveAEResample();
 | 
	
		
			
				|  |  | -+  virtual ~CActiveAEResample();
 | 
	
		
			
				|  |  | -+  bool Init(uint64_t dst_chan_layout, int dst_channels, int dst_rate, AVSampleFormat dst_fmt, int dst_bits, uint64_t src_chan_layout, int src_channels, int src_rate, AVSampleFormat src_fmt, int src_bits, bool upmix, bool normalize, CAEChannelInfo *remapLayout, AEQuality quality);
 | 
	
		
			
				|  |  | -+  int Resample(uint8_t **dst_buffer, int dst_samples, uint8_t **src_buffer, int src_samples, double ratio);
 | 
	
		
			
				|  |  | -+  int64_t GetDelay(int64_t base);
 | 
	
		
			
				|  |  | -+  int GetBufferedSamples();
 | 
	
		
			
				|  |  | -+  int CalcDstSampleCount(int src_samples, int dst_rate, int src_rate);
 | 
	
		
			
				|  |  | -+  int GetSrcBufferSize(int samples);
 | 
	
		
			
				|  |  | -+  int GetDstBufferSize(int samples);
 | 
	
		
			
				|  |  | -+  static uint64_t GetAVChannelLayout(CAEChannelInfo &info);
 | 
	
		
			
				|  |  | -+//  static CAEChannelInfo GetAEChannelLayout(uint64_t layout);
 | 
	
		
			
				|  |  | -+  static AVSampleFormat GetAVSampleFormat(AEDataFormat format);
 | 
	
		
			
				|  |  | -+  static AEDataFormat GetAESampleFormat(AVSampleFormat format, int bits);
 | 
	
		
			
				|  |  | -+  static uint64_t GetAVChannel(enum AEChannel aechannel);
 | 
	
		
			
				|  |  | -+  int GetAVChannelIndex(enum AEChannel aechannel, uint64_t layout);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+protected:
 | 
	
		
			
				|  |  | -+  void DeInit();
 | 
	
		
			
				|  |  | -+  DllAvUtil m_dllAvUtil;
 | 
	
		
			
				|  |  | -+  DllSwResample m_dllSwResample;
 | 
	
		
			
				|  |  | -+  bool m_loaded;
 | 
	
		
			
				|  |  | -+  uint64_t m_src_chan_layout, m_dst_chan_layout;
 | 
	
		
			
				|  |  | -+  int m_src_rate, m_dst_rate;
 | 
	
		
			
				|  |  | -+  int m_src_channels, m_dst_channels;
 | 
	
		
			
				|  |  | -+  AVSampleFormat m_src_fmt, m_dst_fmt;
 | 
	
		
			
				|  |  | -+  int m_src_bits, m_dst_bits;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_input;
 | 
	
		
			
				|  |  | -+  OMX_AUDIO_PARAM_PCMMODETYPE m_pcm_output;
 | 
	
		
			
				|  |  | -+  COMXCoreComponent    m_omx_mixer;
 | 
	
		
			
				|  |  | -+  bool                 m_Initialized;
 | 
	
		
			
				|  |  | -+  AVSampleFormat m_last_src_fmt, m_last_dst_fmt;
 | 
	
		
			
				|  |  | -+  int m_last_src_channels, m_last_dst_channels;
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Makefile.in b/xbmc/cores/AudioEngine/Makefile.in
 | 
	
		
			
				|  |  | -index b49c3cc..2ba50f9 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Makefile.in
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Makefile.in
 | 
	
		
			
				|  |  | -@@ -31,6 +31,7 @@ SRCS += Engines/ActiveAE/ActiveAESink.cpp
 | 
	
		
			
				|  |  | - SRCS += Engines/ActiveAE/ActiveAEStream.cpp
 | 
	
		
			
				|  |  | - SRCS += Engines/ActiveAE/ActiveAESound.cpp
 | 
	
		
			
				|  |  | - SRCS += Engines/ActiveAE/ActiveAEResample.cpp
 | 
	
		
			
				|  |  | -+SRCS += Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | - SRCS += Engines/ActiveAE/ActiveAEBuffer.cpp
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - ifeq (@USE_ANDROID@,1)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/OMXCore.cpp b/xbmc/linux/OMXCore.cpp
 | 
	
		
			
				|  |  | -index 99e407a..8d3c86a 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/OMXCore.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/OMXCore.cpp
 | 
	
		
			
				|  |  | -@@ -448,7 +448,7 @@ void COMXCoreComponent::FlushAll()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COMXCoreComponent::FlushInput()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if(!m_handle)
 | 
	
		
			
				|  |  | -+  if(!m_handle || m_resource_error)
 | 
	
		
			
				|  |  | -     return;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -@@ -470,7 +470,7 @@ void COMXCoreComponent::FlushInput()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COMXCoreComponent::FlushOutput()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  if(!m_handle)
 | 
	
		
			
				|  |  | -+  if(!m_handle || m_resource_error)
 | 
	
		
			
				|  |  | -     return;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err = OMX_ErrorNone;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 07042c916d780bf4acb742e174005aa1e38f3a13 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 27 Mar 2014 00:22:05 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 60/94] [PiResample] Work around AE not providing correct
 | 
	
		
			
				|  |  | - src_bits
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - .../AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp     | 13 +++++++++++--
 | 
	
		
			
				|  |  | - 1 file changed, 11 insertions(+), 2 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -index 1d7b425..a91e208 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -@@ -97,16 +97,25 @@ bool CActiveAEResample::Init(uint64_t dst_chan_layout, int dst_channels, int dst
 | 
	
		
			
				|  |  | -   if (!m_loaded)
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  if (src_bits == 0)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (src_fmt == AV_SAMPLE_FMT_U8) src_bits = 8;
 | 
	
		
			
				|  |  | -+    else if (src_fmt == AV_SAMPLE_FMT_S16) src_bits = 16;
 | 
	
		
			
				|  |  | -+    else if (src_fmt == AV_SAMPLE_FMT_S32) src_bits = 32;
 | 
	
		
			
				|  |  | -+    else if (src_fmt == AV_SAMPLE_FMT_FLT) src_bits = 32;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  assert(src_bits && dst_bits);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   m_dst_chan_layout = dst_chan_layout;
 | 
	
		
			
				|  |  | -   m_dst_channels = dst_channels;
 | 
	
		
			
				|  |  | -   m_dst_rate = dst_rate;
 | 
	
		
			
				|  |  | -   m_dst_fmt = dst_fmt;
 | 
	
		
			
				|  |  | --  m_dst_bits = dst_bits ? dst_bits : 8;
 | 
	
		
			
				|  |  | -+  m_dst_bits = dst_bits;
 | 
	
		
			
				|  |  | -   m_src_chan_layout = src_chan_layout;
 | 
	
		
			
				|  |  | -   m_src_channels = src_channels;
 | 
	
		
			
				|  |  | -   m_src_rate = src_rate;
 | 
	
		
			
				|  |  | -   m_src_fmt = src_fmt;
 | 
	
		
			
				|  |  | --  m_src_bits = src_bits ? src_bits : 8;
 | 
	
		
			
				|  |  | -+  m_src_bits = src_bits;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (m_dst_chan_layout == 0)
 | 
	
		
			
				|  |  | -     m_dst_chan_layout = m_dllAvUtil.av_get_default_channel_layout(m_dst_channels);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 16e8c9550b1afc0a4f5c050cc10c2c19ec9cea38 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Tue, 25 Mar 2014 19:43:07 +0000
 | 
	
		
			
				|  |  | -Subject: [PATCH 61/94] [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
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - lib/ffmpeg/libavformat/wtvdec.c | 18 ++++++++++--------
 | 
	
		
			
				|  |  | - 1 file changed, 10 insertions(+), 8 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/lib/ffmpeg/libavformat/wtvdec.c b/lib/ffmpeg/libavformat/wtvdec.c
 | 
	
		
			
				|  |  | -index e423370..70898bd 100644
 | 
	
		
			
				|  |  | ---- a/lib/ffmpeg/libavformat/wtvdec.c
 | 
	
		
			
				|  |  | -+++ b/lib/ffmpeg/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 (url_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;
 | 
	
		
			
				|  |  | -                 }
 | 
	
		
			
				|  |  | -             }
 | 
	
		
			
				|  |  | -         }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From c95293a4cfd39a5296b434c330c3e6e24831bb6e Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 7 Apr 2014 18:19:32 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 62/94] [rbp/omxplayer] When opening a stream don't try to
 | 
	
		
			
				|  |  | - update gui so often
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/dialogs/GUIDialogBusy.cpp | 4 ++++
 | 
	
		
			
				|  |  | - 1 file changed, 4 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/dialogs/GUIDialogBusy.cpp b/xbmc/dialogs/GUIDialogBusy.cpp
 | 
	
		
			
				|  |  | -index e9ba7d3..0fdc3c2 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/dialogs/GUIDialogBusy.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/dialogs/GUIDialogBusy.cpp
 | 
	
		
			
				|  |  | -@@ -64,7 +64,11 @@ bool CGUIDialogBusy::WaitOnEvent(CEvent &event, unsigned int displaytime /* = 10
 | 
	
		
			
				|  |  | -     if (dialog)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       dialog->Show();
 | 
	
		
			
				|  |  | -+#ifdef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -+      while(!event.WaitMSec(100))
 | 
	
		
			
				|  |  | -+#else
 | 
	
		
			
				|  |  | -       while(!event.WaitMSec(1))
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -         g_windowManager.ProcessRenderLoop(false);
 | 
	
		
			
				|  |  | -         if (allowCancel && dialog->IsCanceled())
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 9420d803f17902c7d9f1e6734ab42a78c5d67572 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 7 Apr 2014 15:28:57 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 63/94] [omxcodec] Clamp video texture at edges to avoid image
 | 
	
		
			
				|  |  | - wrapping
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 ++
 | 
	
		
			
				|  |  | - 1 file changed, 2 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -index a57abe4..e22a153 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -@@ -1339,6 +1339,8 @@ void CLinuxRendererGLES::RenderOpenMax(int index, int field)
 | 
	
		
			
				|  |  | -   GLint filter = m_scalingMethod == VS_SCALINGMETHOD_NEAREST ? GL_NEAREST : GL_LINEAR;
 | 
	
		
			
				|  |  | -   glTexParameteri(m_textureTarget, GL_TEXTURE_MAG_FILTER, filter);
 | 
	
		
			
				|  |  | -   glTexParameteri(m_textureTarget, GL_TEXTURE_MIN_FILTER, filter);
 | 
	
		
			
				|  |  | -+  glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
	
		
			
				|  |  | -+  glTexParameteri(m_textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   g_Windowing.EnableGUIShader(SM_TEXTURE_RGBA);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 49c65c8d083952be840d8730f3fa40cfd5e0211c Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 7 Apr 2014 17:36:19 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 64/94] [PiSink] Remove unneeded header and use CAEChannelInfo
 | 
	
		
			
				|  |  | - directly
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - .../AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp    |  1 -
 | 
	
		
			
				|  |  | - xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp                  | 14 +++++++-------
 | 
	
		
			
				|  |  | - 2 files changed, 7 insertions(+), 8 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -index a91e208..60c5e04 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Engines/ActiveAE/ActiveAEResamplePi.cpp
 | 
	
		
			
				|  |  | -@@ -24,7 +24,6 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "ActiveAEResample.h"
 | 
	
		
			
				|  |  | - #include "linux/RBP.h"
 | 
	
		
			
				|  |  | --#include "cores/omxplayer/PCMRemap.h"
 | 
	
		
			
				|  |  | - #include "settings/Settings.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
 | 
	
		
			
				|  |  | -index 9ce00e3..070e6eb 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
 | 
	
		
			
				|  |  | -@@ -78,9 +78,9 @@ static void SetAudioProps(bool stream_channels, uint32_t channel_map)
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG, "%s:%s hdmi_stream_channels %d hdmi_channel_map %08x", CLASSNAME, __func__, stream_channels, channel_map);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
 | 
	
		
			
				|  |  | -+static uint32_t GetChannelMap(const CAEChannelInfo &channelLayout, bool passthrough)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  unsigned int channels = format.m_channelLayout.Count();
 | 
	
		
			
				|  |  | -+  unsigned int channels = channelLayout.Count();
 | 
	
		
			
				|  |  | -   uint32_t channel_map = 0;
 | 
	
		
			
				|  |  | -   if (passthrough)
 | 
	
		
			
				|  |  | -     return 0;
 | 
	
		
			
				|  |  | -@@ -119,12 +119,12 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
 | 
	
		
			
				|  |  | -   // According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels
 | 
	
		
			
				|  |  | -   // but no BR BL channels, we use the wide map in order to open only the num of channels really
 | 
	
		
			
				|  |  | -   // needed.
 | 
	
		
			
				|  |  | --  if (format.m_channelLayout.HasChannel(AE_CH_BL) && !format.m_channelLayout.HasChannel(AE_CH_SL))
 | 
	
		
			
				|  |  | -+  if (channelLayout.HasChannel(AE_CH_BL) && !channelLayout.HasChannel(AE_CH_SL))
 | 
	
		
			
				|  |  | -     map = map_back;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   for (unsigned int i = 0; i < channels; ++i)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    AEChannel c = format.m_channelLayout[i];
 | 
	
		
			
				|  |  | -+    AEChannel c = channelLayout[i];
 | 
	
		
			
				|  |  | -     unsigned int chan = 0;
 | 
	
		
			
				|  |  | -     if ((unsigned int)c < sizeof map_normal / sizeof *map_normal)
 | 
	
		
			
				|  |  | -       chan = map[(unsigned int)c];
 | 
	
		
			
				|  |  | -@@ -155,9 +155,9 @@ static uint32_t GetChannelMap(AEAudioFormat &format, bool passthrough)
 | 
	
		
			
				|  |  | -     0xff, // 7
 | 
	
		
			
				|  |  | -     0x13, // 7.1
 | 
	
		
			
				|  |  | -   };
 | 
	
		
			
				|  |  | --  uint8_t cea = format.m_channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
 | 
	
		
			
				|  |  | -+  uint8_t cea = channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
 | 
	
		
			
				|  |  | -   if (cea == 0xff)
 | 
	
		
			
				|  |  | --    CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, format.m_channelLayout.HasChannel(AE_CH_LFE), channels);
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, channelLayout.HasChannel(AE_CH_LFE), channels);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   channel_map |= cea << 24;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -189,7 +189,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
 | 
	
		
			
				|  |  | -   format.m_frames        = format.m_sampleRate * AUDIO_PLAYBUFFER;
 | 
	
		
			
				|  |  | -   format.m_frameSamples  = format.m_frames * channels;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  SetAudioProps(m_passthrough, GetChannelMap(format, m_passthrough));
 | 
	
		
			
				|  |  | -+  SetAudioProps(m_passthrough, GetChannelMap(format.m_channelLayout, m_passthrough));
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_format = format;
 | 
	
		
			
				|  |  | -   m_sinkbuffer_sec_per_byte = 1.0 / (double)(m_format.m_frameSize * m_format.m_sampleRate);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 6ce35e828b39e0a8f2d81cb6fb6162edd53468a8 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 7 Apr 2014 17:37:41 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 65/94] [omxplayer] Remove PCMRemap and handle multichannel
 | 
	
		
			
				|  |  | - mixing like ActiveAE does
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - tools/buildsteps/rbpi/config-xbmc-makefile |   4 +-
 | 
	
		
			
				|  |  | - tools/depends/target/alsa-lib/Makefile     |   2 +-
 | 
	
		
			
				|  |  | - tools/depends/target/libcec/Makefile       |   2 +-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/Makefile.in           |   1 -
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudio.cpp          | 395 +++++++++-----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudio.h            |   9 +-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp  |  39 +-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudioCodecOMX.h    |   5 +-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerAudio.cpp    |   4 +-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/PCMRemap.cpp          | 813 -----------------------------
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/PCMRemap.h            | 151 ------
 | 
	
		
			
				|  |  | - 11 files changed, 294 insertions(+), 1131 deletions(-)
 | 
	
		
			
				|  |  | - delete mode 100644 xbmc/cores/omxplayer/PCMRemap.cpp
 | 
	
		
			
				|  |  | - delete mode 100644 xbmc/cores/omxplayer/PCMRemap.h
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/tools/buildsteps/rbpi/config-xbmc-makefile b/tools/buildsteps/rbpi/config-xbmc-makefile
 | 
	
		
			
				|  |  | -index 761a3b4..18600e2 100644
 | 
	
		
			
				|  |  | ---- a/tools/buildsteps/rbpi/config-xbmc-makefile
 | 
	
		
			
				|  |  | -+++ b/tools/buildsteps/rbpi/config-xbmc-makefile
 | 
	
		
			
				|  |  | -@@ -12,10 +12,10 @@ CONFIGURE = cp -f $(CONFIG_SUB) $(CONFIG_GUESS) build-aux/ ;\
 | 
	
		
			
				|  |  | -     --disable-gl --enable-gles --enable-airplay \
 | 
	
		
			
				|  |  | -     --enable-airtunes --enable-libcec --enable-player=omxplayer \
 | 
	
		
			
				|  |  | -     --disable-sdl --disable-x11 --disable-xrandr --disable-openmax \
 | 
	
		
			
				|  |  | --    --disable-optical-drive --disable-dvdcss --disable-joystick \
 | 
	
		
			
				|  |  | -+    --disable-optical-drive --enable-dvdcss --enable-openmax --disable-joystick \
 | 
	
		
			
				|  |  | -     --disable-crystalhd --disable-vtbdecoder --disable-vaapi \
 | 
	
		
			
				|  |  | -     --disable-vdpau --disable-projectm --disable-rsxs --disable-fishbmc \
 | 
	
		
			
				|  |  | --    --disable-alsa
 | 
	
		
			
				|  |  | -+    --enable-alsa
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - all: $(SOURCE)/libxbmc.so
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/tools/depends/target/alsa-lib/Makefile b/tools/depends/target/alsa-lib/Makefile
 | 
	
		
			
				|  |  | -index b03fc19..a04d933 100644
 | 
	
		
			
				|  |  | ---- a/tools/depends/target/alsa-lib/Makefile
 | 
	
		
			
				|  |  | -+++ b/tools/depends/target/alsa-lib/Makefile
 | 
	
		
			
				|  |  | -@@ -19,7 +19,7 @@ CONFIGURE=cp -f $(CONFIG_SUB) $(CONFIG_GUESS) .; \
 | 
	
		
			
				|  |  | -           --with-ctl-plugins=ext \
 | 
	
		
			
				|  |  | -           --with-pcm-plugins="copy,linear,route,mulaw,alaw,adpcm,rate,plug,multi,file,null,empty,share,meter,hooks,lfloat,ladspa,asym,iec958,softvol,extplug,ioplug,mmap_emul" \
 | 
	
		
			
				|  |  | -           --disable-resmgr --enable-aload --enable-mixer  --enable-pcm  --disable-rawmidi  --enable-hwdep  --disable-seq  --disable-alisp  --disable-old-symbols --disable-python \
 | 
	
		
			
				|  |  | --          --with-softfloat=yes --with-libdl=yes --with-pthread=yes --with-librt=no --disable-shared \
 | 
	
		
			
				|  |  | -+          --with-softfloat=yes --with-libdl=yes --with-pthread=yes --with-librt=no --enable-shared \
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - LIBDYLIB=$(PLATFORM)/src/.libs/$(LIBNAME).a
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/tools/depends/target/libcec/Makefile b/tools/depends/target/libcec/Makefile
 | 
	
		
			
				|  |  | -index 16fec1b..d18f1c8 100644
 | 
	
		
			
				|  |  | ---- a/tools/depends/target/libcec/Makefile
 | 
	
		
			
				|  |  | -+++ b/tools/depends/target/libcec/Makefile
 | 
	
		
			
				|  |  | -@@ -8,7 +8,7 @@ SOURCE=$(LIBNAME)-$(VERSION)-2
 | 
	
		
			
				|  |  | - ARCHIVE=$(SOURCE).tar.gz
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - # configuration settings
 | 
	
		
			
				|  |  | --CONFIGURE=./configure --prefix=$(PREFIX) --disable-rpi \
 | 
	
		
			
				|  |  | -+CONFIGURE=./configure --prefix=$(PREFIX) --enable-rpi \
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - LIBDYLIB=$(PLATFORM)/src/lib/.libs/libcec.la
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/Makefile.in b/xbmc/cores/omxplayer/Makefile.in
 | 
	
		
			
				|  |  | -index 3163282..e5cad70 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/Makefile.in
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/Makefile.in
 | 
	
		
			
				|  |  | -@@ -7,7 +7,6 @@ SRCS += OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | - SRCS += OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | - SRCS += OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | - SRCS += OMXImage.cpp
 | 
	
		
			
				|  |  | --SRCS += PCMRemap.cpp
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - LIB = omxplayer.a
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -index 72e42ec..d9beb68 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -@@ -29,6 +29,7 @@
 | 
	
		
			
				|  |  | - #include "OMXAudio.h"
 | 
	
		
			
				|  |  | - #include "Application.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | -+#include "linux/RBP.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define CLASSNAME "COMXAudio"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -40,6 +41,7 @@
 | 
	
		
			
				|  |  | - #include "guilib/LocalizeStrings.h"
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Utils/AEConvert.h"
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/AEFactory.h"
 | 
	
		
			
				|  |  | -+#include "DllSwResample.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - using namespace std;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -404,28 +406,147 @@ bool COMXAudio::PortSettingsChanged()
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --static unsigned count_bits(int64_t value)
 | 
	
		
			
				|  |  | -+static uint64_t GetAVChannelLayout(CAEChannelInfo &info)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  unsigned bits = 0;
 | 
	
		
			
				|  |  | --  for(;value;++bits)
 | 
	
		
			
				|  |  | --    value &= value - 1;
 | 
	
		
			
				|  |  | --  return bits;
 | 
	
		
			
				|  |  | -+  #ifdef DEBUG_VERBOSE
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGINFO, "%s::%s", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -+  #endif
 | 
	
		
			
				|  |  | -+  uint64_t channelLayout = 0;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FL))   channelLayout |= AV_CH_FRONT_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FR))   channelLayout |= AV_CH_FRONT_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FC))   channelLayout |= AV_CH_FRONT_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_LFE))  channelLayout |= AV_CH_LOW_FREQUENCY;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_BL))   channelLayout |= AV_CH_BACK_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_BR))   channelLayout |= AV_CH_BACK_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FLOC)) channelLayout |= AV_CH_FRONT_LEFT_OF_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_FROC)) channelLayout |= AV_CH_FRONT_RIGHT_OF_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_BC))   channelLayout |= AV_CH_BACK_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_SL))   channelLayout |= AV_CH_SIDE_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_SR))   channelLayout |= AV_CH_SIDE_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TC))   channelLayout |= AV_CH_TOP_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TFL))  channelLayout |= AV_CH_TOP_FRONT_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TFC))  channelLayout |= AV_CH_TOP_FRONT_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TFR))  channelLayout |= AV_CH_TOP_FRONT_RIGHT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TBL))   channelLayout |= AV_CH_TOP_BACK_LEFT;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TBC))   channelLayout |= AV_CH_TOP_BACK_CENTER;
 | 
	
		
			
				|  |  | -+  if (info.HasChannel(AE_CH_TBR))   channelLayout |= AV_CH_TOP_BACK_RIGHT;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return channelLayout;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+static void SetAudioProps(bool stream_channels, uint32_t channel_map)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  char command[80], response[80];
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  sprintf(command, "hdmi_stream_channels %d", stream_channels ? 1 : 0);
 | 
	
		
			
				|  |  | -+  vc_gencmd(response, sizeof response, command);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  sprintf(command, "hdmi_channel_map 0x%08x", channel_map);
 | 
	
		
			
				|  |  | -+  vc_gencmd(response, sizeof response, command);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s:%s hdmi_stream_channels %d hdmi_channel_map %08x", CLASSNAME, __func__, stream_channels, channel_map);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+static uint32_t GetChannelMap(const CAEChannelInfo &channelLayout, bool passthrough)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  unsigned int channels = channelLayout.Count();
 | 
	
		
			
				|  |  | -+  uint32_t channel_map = 0;
 | 
	
		
			
				|  |  | -+  if (passthrough)
 | 
	
		
			
				|  |  | -+    return 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  static const unsigned char map_normal[] =
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    0, //AE_CH_RAW ,
 | 
	
		
			
				|  |  | -+    1, //AE_CH_FL
 | 
	
		
			
				|  |  | -+    2, //AE_CH_FR
 | 
	
		
			
				|  |  | -+    4, //AE_CH_FC
 | 
	
		
			
				|  |  | -+    3, //AE_CH_LFE
 | 
	
		
			
				|  |  | -+    7, //AE_CH_BL
 | 
	
		
			
				|  |  | -+    8, //AE_CH_BR
 | 
	
		
			
				|  |  | -+    1, //AE_CH_FLOC,
 | 
	
		
			
				|  |  | -+    2, //AE_CH_FROC,
 | 
	
		
			
				|  |  | -+    4, //AE_CH_BC,
 | 
	
		
			
				|  |  | -+    5, //AE_CH_SL
 | 
	
		
			
				|  |  | -+    6, //AE_CH_SR
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+  static const unsigned char map_back[] =
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    0, //AE_CH_RAW ,
 | 
	
		
			
				|  |  | -+    1, //AE_CH_FL
 | 
	
		
			
				|  |  | -+    2, //AE_CH_FR
 | 
	
		
			
				|  |  | -+    4, //AE_CH_FC
 | 
	
		
			
				|  |  | -+    3, //AE_CH_LFE
 | 
	
		
			
				|  |  | -+    5, //AE_CH_BL
 | 
	
		
			
				|  |  | -+    6, //AE_CH_BR
 | 
	
		
			
				|  |  | -+    1, //AE_CH_FLOC,
 | 
	
		
			
				|  |  | -+    2, //AE_CH_FROC,
 | 
	
		
			
				|  |  | -+    4, //AE_CH_BC,
 | 
	
		
			
				|  |  | -+    5, //AE_CH_SL
 | 
	
		
			
				|  |  | -+    6, //AE_CH_SR
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+  const unsigned char *map = map_normal;
 | 
	
		
			
				|  |  | -+  // According to CEA-861-D only RL and RR are known. In case of a format having SL and SR channels
 | 
	
		
			
				|  |  | -+  // but no BR BL channels, we use the wide map in order to open only the num of channels really
 | 
	
		
			
				|  |  | -+  // needed.
 | 
	
		
			
				|  |  | -+  if (channelLayout.HasChannel(AE_CH_BL) && !channelLayout.HasChannel(AE_CH_SL))
 | 
	
		
			
				|  |  | -+    map = map_back;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  for (unsigned int i = 0; i < channels; ++i)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    AEChannel c = channelLayout[i];
 | 
	
		
			
				|  |  | -+    unsigned int chan = 0;
 | 
	
		
			
				|  |  | -+    if ((unsigned int)c < sizeof map_normal / sizeof *map_normal)
 | 
	
		
			
				|  |  | -+      chan = map[(unsigned int)c];
 | 
	
		
			
				|  |  | -+    if (chan > 0)
 | 
	
		
			
				|  |  | -+      channel_map |= (chan-1) << (3*i);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  // These numbers are from Table 28 Audio InfoFrame Data byte 4 of CEA 861
 | 
	
		
			
				|  |  | -+  // and describe the speaker layout
 | 
	
		
			
				|  |  | -+  static const uint8_t cea_map[] = {
 | 
	
		
			
				|  |  | -+    0xff, // 0
 | 
	
		
			
				|  |  | -+    0xff, // 1
 | 
	
		
			
				|  |  | -+    0x00, // 2.0
 | 
	
		
			
				|  |  | -+    0x02, // 3.0
 | 
	
		
			
				|  |  | -+    0x08, // 4.0
 | 
	
		
			
				|  |  | -+    0x0a, // 5.0
 | 
	
		
			
				|  |  | -+    0xff, // 6
 | 
	
		
			
				|  |  | -+    0x12, // 7.0
 | 
	
		
			
				|  |  | -+    0xff, // 8
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+  static const uint8_t cea_map_lfe[] = {
 | 
	
		
			
				|  |  | -+    0xff, // 0
 | 
	
		
			
				|  |  | -+    0xff, // 1
 | 
	
		
			
				|  |  | -+    0xff, // 2
 | 
	
		
			
				|  |  | -+    0x01, // 2.1
 | 
	
		
			
				|  |  | -+    0x03, // 3.1
 | 
	
		
			
				|  |  | -+    0x09, // 4.1
 | 
	
		
			
				|  |  | -+    0x0b, // 5.1
 | 
	
		
			
				|  |  | -+    0xff, // 7
 | 
	
		
			
				|  |  | -+    0x13, // 7.1
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+  uint8_t cea = channelLayout.HasChannel(AE_CH_LFE) ? cea_map_lfe[channels] : cea_map[channels];
 | 
	
		
			
				|  |  | -+  if (cea == 0xff)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s::%s - Unexpected CEA mapping %d,%d", CLASSNAME, __func__, channelLayout.HasChannel(AE_CH_LFE), channels);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  channel_map |= cea << 24;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return channel_map;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, uint64_t channelMap, bool bUsePassthrough, bool bUseHWDecode)
 | 
	
		
			
				|  |  | -+bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, CAEChannelInfo channelMap, bool bUsePassthrough, bool bUseHWDecode)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   CSingleLock lock (m_critSection);
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   Deinitialize();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if(!m_dllAvUtil.Load())
 | 
	
		
			
				|  |  | -+  if (!m_dllAvUtil.Load())
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_HWDecode    = bUseHWDecode;
 | 
	
		
			
				|  |  | -   m_Passthrough = bUsePassthrough;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_InputChannels = count_bits(channelMap);
 | 
	
		
			
				|  |  | -+  m_InputChannels = channelMap.Count();
 | 
	
		
			
				|  |  | -   m_format = format;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(m_InputChannels == 0)
 | 
	
		
			
				|  |  | -@@ -471,26 +592,133 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (!m_Passthrough)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    enum PCMChannels inLayout[OMX_AUDIO_MAXCHANNELS];
 | 
	
		
			
				|  |  | --    enum PCMChannels outLayout[OMX_AUDIO_MAXCHANNELS];
 | 
	
		
			
				|  |  | --    enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
 | 
	
		
			
				|  |  | -+    bool upmix = CSettings::Get().GetBool("audiooutput.stereoupmix");
 | 
	
		
			
				|  |  | -+    bool normalize = CSettings::Get().GetBool("audiooutput.normalizelevels");
 | 
	
		
			
				|  |  | -+    void *remapLayout = NULL;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    CAEChannelInfo stdLayout = (enum AEStdChLayout)CSettings::Get().GetInt("audiooutput.channels");
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     // ignore layout setting for analogue
 | 
	
		
			
				|  |  | -     if (CSettings::Get().GetBool("audiooutput.dualaudio") || CSettings::Get().GetString("audiooutput.audiodevice") == "PI:Analogue")
 | 
	
		
			
				|  |  | --      layout = PCM_LAYOUT_2_0;
 | 
	
		
			
				|  |  | -+      stdLayout = AE_CH_LAYOUT_2_0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     // force out layout to stereo if input is not multichannel - it gives the receiver a chance to upmix
 | 
	
		
			
				|  |  | --    if (channelMap == (AV_CH_FRONT_LEFT | AV_CH_FRONT_RIGHT) || channelMap == AV_CH_FRONT_CENTER)
 | 
	
		
			
				|  |  | --      layout = PCM_LAYOUT_2_0;
 | 
	
		
			
				|  |  | --    BuildChannelMap(inLayout, channelMap);
 | 
	
		
			
				|  |  | --    m_OutputChannels = BuildChannelMapCEA(outLayout, GetChannelLayout(layout));
 | 
	
		
			
				|  |  | --    CPCMRemap m_remap;
 | 
	
		
			
				|  |  | --    m_remap.Reset();
 | 
	
		
			
				|  |  | --    /*outLayout = */m_remap.SetInputFormat (m_InputChannels, inLayout, CAEUtil::DataFormatToBits(m_format.m_dataFormat) / 8, m_format.m_sampleRate, layout);
 | 
	
		
			
				|  |  | --    m_remap.SetOutputFormat(m_OutputChannels, outLayout);
 | 
	
		
			
				|  |  | --    m_remap.GetDownmixMatrix(m_downmix_matrix);
 | 
	
		
			
				|  |  | --    m_wave_header.dwChannelMask = channelMap;
 | 
	
		
			
				|  |  | --    BuildChannelMapOMX(m_input_channels, channelMap);
 | 
	
		
			
				|  |  | --    BuildChannelMapOMX(m_output_channels, GetChannelLayout(layout));
 | 
	
		
			
				|  |  | -+    if (m_InputChannels <= 2)
 | 
	
		
			
				|  |  | -+      stdLayout = AE_CH_LAYOUT_2_0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    uint64_t m_dst_chan_layout = GetAVChannelLayout(stdLayout);
 | 
	
		
			
				|  |  | -+    uint64_t m_src_chan_layout = GetAVChannelLayout(channelMap);
 | 
	
		
			
				|  |  | -+    m_OutputChannels = stdLayout.Count();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    int m_dst_channels = m_OutputChannels;
 | 
	
		
			
				|  |  | -+    int m_src_channels = m_InputChannels;
 | 
	
		
			
				|  |  | -+    SetAudioProps(m_Passthrough, GetChannelMap(stdLayout, m_Passthrough));
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d norm:%d upmix:%d %llx:%llx", CLASSNAME, __func__, remapLayout, m_src_channels, m_dst_channels, normalize, upmix, m_src_chan_layout, m_dst_chan_layout);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    // this code is just uses ffmpeg to produce the 8x8 mixing matrix
 | 
	
		
			
				|  |  | -+    // dummy sample rate and format, as we only care about channel mapping
 | 
	
		
			
				|  |  | -+    DllSwResample m_dllSwResample;
 | 
	
		
			
				|  |  | -+    if (!m_dllSwResample.Load())
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    SwrContext *m_pContext = m_dllSwResample.swr_alloc_set_opts(NULL, m_dst_chan_layout, AV_SAMPLE_FMT_FLT, 48000,
 | 
	
		
			
				|  |  | -+                                                          m_src_chan_layout, AV_SAMPLE_FMT_FLT, 48000, 0, NULL);
 | 
	
		
			
				|  |  | -+    if(!m_pContext)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "COMXAudio::Init - create context failed");
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    // tell resampler to clamp float values
 | 
	
		
			
				|  |  | -+    // not required for sink stage (remapLayout == true)
 | 
	
		
			
				|  |  | -+    if (!remapLayout && normalize)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+       av_opt_set_double(m_pContext, "rematrix_maxval", 1.0, 0);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    // stereo upmix
 | 
	
		
			
				|  |  | -+    if (upmix && m_src_channels == 2 && m_dst_channels > 2)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      double m_rematrix[AE_CH_MAX][AE_CH_MAX];
 | 
	
		
			
				|  |  | -+      memset(m_rematrix, 0, sizeof(m_rematrix));
 | 
	
		
			
				|  |  | -+      for (int out=0; out<m_dst_channels; out++)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        uint64_t out_chan = m_dllAvUtil.av_channel_layout_extract_channel(m_dst_chan_layout, out);
 | 
	
		
			
				|  |  | -+        switch(out_chan)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          case AV_CH_FRONT_LEFT:
 | 
	
		
			
				|  |  | -+          case AV_CH_BACK_LEFT:
 | 
	
		
			
				|  |  | -+          case AV_CH_SIDE_LEFT:
 | 
	
		
			
				|  |  | -+            m_rematrix[out][0] = 1.0;
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+          case AV_CH_FRONT_RIGHT:
 | 
	
		
			
				|  |  | -+          case AV_CH_BACK_RIGHT:
 | 
	
		
			
				|  |  | -+          case AV_CH_SIDE_RIGHT:
 | 
	
		
			
				|  |  | -+            m_rematrix[out][1] = 1.0;
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+          case AV_CH_FRONT_CENTER:
 | 
	
		
			
				|  |  | -+            m_rematrix[out][0] = 0.5;
 | 
	
		
			
				|  |  | -+            m_rematrix[out][1] = 0.5;
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+          case AV_CH_LOW_FREQUENCY:
 | 
	
		
			
				|  |  | -+            m_rematrix[out][0] = 0.5;
 | 
	
		
			
				|  |  | -+            m_rematrix[out][1] = 0.5;
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+          default:
 | 
	
		
			
				|  |  | -+            break;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+      if (m_dllSwResample.swr_set_matrix(m_pContext, (const double*)m_rematrix, AE_CH_MAX) < 0)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGERROR, "COMXAudio::Init - setting channel matrix failed");
 | 
	
		
			
				|  |  | -+        return false;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (m_dllSwResample.swr_init(m_pContext) < 0)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "COMXAudio::Init - init resampler failed");
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    const int samples = 8;
 | 
	
		
			
				|  |  | -+    uint8_t *output, *input;
 | 
	
		
			
				|  |  | -+    av_samples_alloc(&output, NULL, m_dst_channels, samples, AV_SAMPLE_FMT_FLT, 1);
 | 
	
		
			
				|  |  | -+    av_samples_alloc(&input , NULL, m_src_channels, samples, AV_SAMPLE_FMT_FLT, 1);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    // Produce "identity" samples
 | 
	
		
			
				|  |  | -+    float *f = (float *)input;
 | 
	
		
			
				|  |  | -+    for (int j=0; j < samples; j++)
 | 
	
		
			
				|  |  | -+      for (int i=0; i < m_src_channels; i++)
 | 
	
		
			
				|  |  | -+        *f++ = i == j ? 1.0f : 0.0f;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    int ret = m_dllSwResample.swr_convert(m_pContext, &output, samples, (const uint8_t **)&input, samples);
 | 
	
		
			
				|  |  | -+    if (ret < 0)
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "COMXAudio::Resample - resample failed");
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    f = (float *)output;
 | 
	
		
			
				|  |  | -+    for (int j=0; j < 8; j++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      for (int i=0; i < m_dst_channels; i++)
 | 
	
		
			
				|  |  | -+        m_downmix_matrix[8*i+j] = *f++;
 | 
	
		
			
				|  |  | -+      for (int i=m_dst_channels; i < 8; i++)
 | 
	
		
			
				|  |  | -+        m_downmix_matrix[8*i+j] = 0.0f;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    for (int j=0; j < 8; j++)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      char s[128] = {}, *t=s;
 | 
	
		
			
				|  |  | -+      for (int i=0; i < 8; i++)
 | 
	
		
			
				|  |  | -+        t += sprintf(t, "% 6.2f ", m_downmix_matrix[j*8+i]);
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGINFO, "%s::%s  %s", CLASSNAME, __func__, s);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    av_freep(&input);
 | 
	
		
			
				|  |  | -+    av_freep(&output);
 | 
	
		
			
				|  |  | -+    m_dllSwResample.swr_free(&m_pContext);
 | 
	
		
			
				|  |  | -+    m_dllSwResample.Unload();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    m_wave_header.dwChannelMask = m_src_chan_layout;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_SampleRate    = m_format.m_sampleRate;
 | 
	
		
			
				|  |  | -@@ -1605,122 +1833,3 @@ void COMXAudio::CheckOutputBufferSize(void **buffer, int *oldSize, int newSize)
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   memset(*buffer, 0x0, *oldSize);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void COMXAudio::BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  int index = 0;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_LEFT           ) channelMap[index++] = PCM_FRONT_LEFT           ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_RIGHT          ) channelMap[index++] = PCM_FRONT_RIGHT          ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_CENTER         ) channelMap[index++] = PCM_FRONT_CENTER         ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_LOW_FREQUENCY        ) channelMap[index++] = PCM_LOW_FREQUENCY        ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_LEFT            ) channelMap[index++] = PCM_BACK_LEFT            ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_RIGHT           ) channelMap[index++] = PCM_BACK_RIGHT           ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = PCM_FRONT_LEFT_OF_CENTER ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = PCM_FRONT_RIGHT_OF_CENTER;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_CENTER          ) channelMap[index++] = PCM_BACK_CENTER          ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_LEFT            ) channelMap[index++] = PCM_SIDE_LEFT            ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_RIGHT           ) channelMap[index++] = PCM_SIDE_RIGHT           ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_CENTER           ) channelMap[index++] = PCM_TOP_CENTER           ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_LEFT       ) channelMap[index++] = PCM_TOP_FRONT_LEFT       ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_CENTER     ) channelMap[index++] = PCM_TOP_FRONT_CENTER     ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_RIGHT      ) channelMap[index++] = PCM_TOP_FRONT_RIGHT      ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_LEFT        ) channelMap[index++] = PCM_TOP_BACK_LEFT        ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_CENTER      ) channelMap[index++] = PCM_TOP_BACK_CENTER      ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_RIGHT       ) channelMap[index++] = PCM_TOP_BACK_RIGHT       ;
 | 
	
		
			
				|  |  | --  while (index<OMX_AUDIO_MAXCHANNELS)
 | 
	
		
			
				|  |  | --    channelMap[index++] = PCM_INVALID;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --// See CEA spec: Table 20, Audio InfoFrame data byte 4 for the ordering here
 | 
	
		
			
				|  |  | --int COMXAudio::BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  int index = 0;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_LEFT           ) channelMap[index++] = PCM_FRONT_LEFT;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_RIGHT          ) channelMap[index++] = PCM_FRONT_RIGHT;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_LOW_FREQUENCY        ) channelMap[index++] = PCM_LOW_FREQUENCY;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_CENTER         ) channelMap[index++] = PCM_FRONT_CENTER;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_LEFT            ) channelMap[index++] = PCM_BACK_LEFT;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_RIGHT           ) channelMap[index++] = PCM_BACK_RIGHT;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_LEFT            ) channelMap[index++] = PCM_SIDE_LEFT;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_RIGHT           ) channelMap[index++] = PCM_SIDE_RIGHT;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  while (index<OMX_AUDIO_MAXCHANNELS)
 | 
	
		
			
				|  |  | --    channelMap[index++] = PCM_INVALID;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  int num_channels = 0;
 | 
	
		
			
				|  |  | --  for (index=0; index<OMX_AUDIO_MAXCHANNELS; index++)
 | 
	
		
			
				|  |  | --    if (channelMap[index] != PCM_INVALID)
 | 
	
		
			
				|  |  | --       num_channels = index+1;
 | 
	
		
			
				|  |  | --  return num_channels;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void COMXAudio::BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE *	channelMap, uint64_t layout)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  int index = 0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_LEFT           ) channelMap[index++] = OMX_AUDIO_ChannelLF;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_RIGHT          ) channelMap[index++] = OMX_AUDIO_ChannelRF;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_CENTER         ) channelMap[index++] = OMX_AUDIO_ChannelCF;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_LOW_FREQUENCY        ) channelMap[index++] = OMX_AUDIO_ChannelLFE;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_LEFT            ) channelMap[index++] = OMX_AUDIO_ChannelLR;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_RIGHT           ) channelMap[index++] = OMX_AUDIO_ChannelRR;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_LEFT            ) channelMap[index++] = OMX_AUDIO_ChannelLS;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_RIGHT           ) channelMap[index++] = OMX_AUDIO_ChannelRS;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_CENTER          ) channelMap[index++] = OMX_AUDIO_ChannelCS;
 | 
	
		
			
				|  |  | --  // following are not in openmax spec, but gpu does accept them
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)10;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)11;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_CENTER           ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)12;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_LEFT       ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)13;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_CENTER     ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)14;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_RIGHT      ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)15;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_LEFT        ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)16;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_CENTER      ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)17;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_RIGHT       ) channelMap[index++] = (enum OMX_AUDIO_CHANNELTYPE)18;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  while (index<OMX_AUDIO_MAXCHANNELS)
 | 
	
		
			
				|  |  | --    channelMap[index++] = OMX_AUDIO_ChannelNone;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --uint64_t COMXAudio::GetChannelLayout(enum PCMLayout layout)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  uint64_t layouts[] = {
 | 
	
		
			
				|  |  | --    /* 2.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT,
 | 
	
		
			
				|  |  | --    /* 2.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_LOW_FREQUENCY,
 | 
	
		
			
				|  |  | --    /* 3.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER,
 | 
	
		
			
				|  |  | --    /* 3.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_LOW_FREQUENCY,
 | 
	
		
			
				|  |  | --    /* 4.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
 | 
	
		
			
				|  |  | --    /* 4.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
 | 
	
		
			
				|  |  | --    /* 5.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
 | 
	
		
			
				|  |  | --    /* 5.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY,
 | 
	
		
			
				|  |  | --    /* 7.0 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT,
 | 
	
		
			
				|  |  | --    /* 7.1 */ 1<<PCM_FRONT_LEFT | 1<<PCM_FRONT_RIGHT | 1<<PCM_FRONT_CENTER | 1<<PCM_SIDE_LEFT | 1<<PCM_SIDE_RIGHT | 1<<PCM_BACK_LEFT | 1<<PCM_BACK_RIGHT | 1<<PCM_LOW_FREQUENCY
 | 
	
		
			
				|  |  | --  };
 | 
	
		
			
				|  |  | --  return (int)layout < 10 ? layouts[(int)layout] : 0;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CAEChannelInfo COMXAudio::GetAEChannelLayout(uint64_t layout)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  CAEChannelInfo m_channelLayout;
 | 
	
		
			
				|  |  | --  m_channelLayout.Reset();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_LEFT           ) m_channelLayout += AE_CH_FL  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_RIGHT          ) m_channelLayout += AE_CH_FR  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_CENTER         ) m_channelLayout += AE_CH_FC  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_LOW_FREQUENCY        ) m_channelLayout += AE_CH_LFE ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_LEFT            ) m_channelLayout += AE_CH_BL  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_RIGHT           ) m_channelLayout += AE_CH_BR  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_BACK_CENTER          ) m_channelLayout += AE_CH_BC  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_LEFT            ) m_channelLayout += AE_CH_SL  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_SIDE_RIGHT           ) m_channelLayout += AE_CH_SR  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_CENTER           ) m_channelLayout += AE_CH_TC  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_LEFT       ) m_channelLayout += AE_CH_TFL ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_CENTER     ) m_channelLayout += AE_CH_TFC ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_FRONT_RIGHT      ) m_channelLayout += AE_CH_TFR ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_LEFT        ) m_channelLayout += AE_CH_BL  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_CENTER      ) m_channelLayout += AE_CH_BC  ;
 | 
	
		
			
				|  |  | --  if (layout & AV_CH_TOP_BACK_RIGHT       ) m_channelLayout += AE_CH_BR  ;
 | 
	
		
			
				|  |  | --  return m_channelLayout;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudio.h b/xbmc/cores/omxplayer/OMXAudio.h
 | 
	
		
			
				|  |  | -index b0264d8..a1c59da 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudio.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudio.h
 | 
	
		
			
				|  |  | -@@ -38,7 +38,6 @@
 | 
	
		
			
				|  |  | - #include "OMXCore.h"
 | 
	
		
			
				|  |  | - #include "DllAvCodec.h"
 | 
	
		
			
				|  |  | - #include "DllAvUtil.h"
 | 
	
		
			
				|  |  | --#include "PCMRemap.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "threads/CriticalSection.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -61,7 +60,7 @@ class COMXAudio
 | 
	
		
			
				|  |  | -   float GetCacheTime();
 | 
	
		
			
				|  |  | -   float GetCacheTotal();
 | 
	
		
			
				|  |  | -   COMXAudio();
 | 
	
		
			
				|  |  | --  bool Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, uint64_t channelMap, bool bUsePassthrough, bool bUseHWDecode);
 | 
	
		
			
				|  |  | -+  bool Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo &hints, CAEChannelInfo channelMap, bool bUsePassthrough, bool bUseHWDecode);
 | 
	
		
			
				|  |  | -   bool PortSettingsChanged();
 | 
	
		
			
				|  |  | -   ~COMXAudio();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -99,12 +98,6 @@ class COMXAudio
 | 
	
		
			
				|  |  | -   unsigned int GetAudioRenderingLatency();
 | 
	
		
			
				|  |  | -   float GetMaxLevel(double &pts);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  void BuildChannelMap(enum PCMChannels *channelMap, uint64_t layout);
 | 
	
		
			
				|  |  | --  int BuildChannelMapCEA(enum PCMChannels *channelMap, uint64_t layout);
 | 
	
		
			
				|  |  | --  void BuildChannelMapOMX(enum OMX_AUDIO_CHANNELTYPE *channelMap, uint64_t layout);
 | 
	
		
			
				|  |  | --  uint64_t GetChannelLayout(enum PCMLayout layout);
 | 
	
		
			
				|  |  | --  CAEChannelInfo GetAEChannelLayout(uint64_t layout);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - private:
 | 
	
		
			
				|  |  | -   IAudioCallback* m_pCallback;
 | 
	
		
			
				|  |  | -   bool          m_Initialized;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -index 7f6ef6e..5e47317 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.cpp
 | 
	
		
			
				|  |  | -@@ -26,7 +26,6 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include "cores/AudioEngine/Utils/AEUtil.h"
 | 
	
		
			
				|  |  | - #include "settings/Settings.h"
 | 
	
		
			
				|  |  | --#include "PCMRemap.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - // the size of the audio_render output port buffers
 | 
	
		
			
				|  |  | - #define AUDIO_DECODE_OUTPUT_BUFFER (32*1024)
 | 
	
		
			
				|  |  | -@@ -93,12 +92,11 @@ bool COMXAudioCodecOMX::Open(CDVDStreamInfo &hints)
 | 
	
		
			
				|  |  | -   m_pCodecContext->block_align = hints.blockalign;
 | 
	
		
			
				|  |  | -   m_pCodecContext->bit_rate = hints.bitrate;
 | 
	
		
			
				|  |  | -   m_pCodecContext->bits_per_coded_sample = hints.bitspersample;
 | 
	
		
			
				|  |  | --  enum PCMLayout layout = (enum PCMLayout)std::max(0, CSettings::Get().GetInt("audiooutput.channels")-1);
 | 
	
		
			
				|  |  | -   if (hints.codec == AV_CODEC_ID_TRUEHD)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if (layout == PCM_LAYOUT_2_0)
 | 
	
		
			
				|  |  | -+    if (CSettings::Get().GetInt("audiooutput.channels") == AE_CH_LAYOUT_2_0)
 | 
	
		
			
				|  |  | -       m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_STEREO;
 | 
	
		
			
				|  |  | --    else if (layout <= PCM_LAYOUT_5_1)
 | 
	
		
			
				|  |  | -+    else if (CSettings::Get().GetInt("audiooutput.channels") == AE_CH_LAYOUT_5_1)
 | 
	
		
			
				|  |  | -       m_pCodecContext->request_channel_layout = AV_CH_LAYOUT_5POINT1;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   if (m_pCodecContext->request_channel_layout)
 | 
	
		
			
				|  |  | -@@ -323,7 +321,7 @@ int COMXAudioCodecOMX::GetBitRate()
 | 
	
		
			
				|  |  | -   return m_pCodecContext->bit_rate;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --static unsigned count_bits(int64_t value)
 | 
	
		
			
				|  |  | -+static unsigned count_bits(uint64_t value)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   unsigned bits = 0;
 | 
	
		
			
				|  |  | -   for(;value;++bits)
 | 
	
		
			
				|  |  | -@@ -331,9 +329,10 @@ static unsigned count_bits(int64_t value)
 | 
	
		
			
				|  |  | -   return bits;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --uint64_t COMXAudioCodecOMX::GetChannelMap()
 | 
	
		
			
				|  |  | -+void COMXAudioCodecOMX::BuildChannelMap()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   uint64_t layout;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   int bits = count_bits(m_pCodecContext->channel_layout);
 | 
	
		
			
				|  |  | -   if (bits == m_pCodecContext->channels)
 | 
	
		
			
				|  |  | -     layout = m_pCodecContext->channel_layout;
 | 
	
		
			
				|  |  | -@@ -342,5 +341,31 @@ uint64_t COMXAudioCodecOMX::GetChannelMap()
 | 
	
		
			
				|  |  | -     CLog::Log(LOGINFO, "COMXAudioCodecOMX::GetChannelMap - FFmpeg reported %d channels, but the layout contains %d ignoring", m_pCodecContext->channels, bits);
 | 
	
		
			
				|  |  | -     layout = m_dllAvUtil.av_get_default_channel_layout(m_pCodecContext->channels);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  return layout;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_channelLayout.Reset();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_FRONT_LEFT           ) m_channelLayout += AE_CH_FL  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_FRONT_RIGHT          ) m_channelLayout += AE_CH_FR  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_FRONT_CENTER         ) m_channelLayout += AE_CH_FC  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_LOW_FREQUENCY        ) m_channelLayout += AE_CH_LFE ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_BACK_LEFT            ) m_channelLayout += AE_CH_BL  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_BACK_RIGHT           ) m_channelLayout += AE_CH_BR  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_FRONT_LEFT_OF_CENTER ) m_channelLayout += AE_CH_FLOC;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_FRONT_RIGHT_OF_CENTER) m_channelLayout += AE_CH_FROC;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_BACK_CENTER          ) m_channelLayout += AE_CH_BC  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_SIDE_LEFT            ) m_channelLayout += AE_CH_SL  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_SIDE_RIGHT           ) m_channelLayout += AE_CH_SR  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_TOP_CENTER           ) m_channelLayout += AE_CH_TC  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_TOP_FRONT_LEFT       ) m_channelLayout += AE_CH_TFL ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_TOP_FRONT_CENTER     ) m_channelLayout += AE_CH_TFC ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_TOP_FRONT_RIGHT      ) m_channelLayout += AE_CH_TFR ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_TOP_BACK_LEFT        ) m_channelLayout += AE_CH_BL  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_TOP_BACK_CENTER      ) m_channelLayout += AE_CH_BC  ;
 | 
	
		
			
				|  |  | -+  if (layout & AV_CH_TOP_BACK_RIGHT       ) m_channelLayout += AE_CH_BR  ;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+CAEChannelInfo COMXAudioCodecOMX::GetChannelMap()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  BuildChannelMap();
 | 
	
		
			
				|  |  | -+  return m_channelLayout;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
 | 
	
		
			
				|  |  | -index 66e5b4a..6e6b226 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudioCodecOMX.h
 | 
	
		
			
				|  |  | -@@ -40,7 +40,8 @@ class COMXAudioCodecOMX
 | 
	
		
			
				|  |  | -   int GetData(BYTE** dst, double &dts, double &pts);
 | 
	
		
			
				|  |  | -   void Reset();
 | 
	
		
			
				|  |  | -   int GetChannels();
 | 
	
		
			
				|  |  | --  uint64_t GetChannelMap();
 | 
	
		
			
				|  |  | -+  void BuildChannelMap();
 | 
	
		
			
				|  |  | -+  CAEChannelInfo GetChannelMap();
 | 
	
		
			
				|  |  | -   int GetSampleRate();
 | 
	
		
			
				|  |  | -   int GetBitsPerSample();
 | 
	
		
			
				|  |  | -   static const char* GetName() { return "FFmpeg"; }
 | 
	
		
			
				|  |  | -@@ -62,7 +63,7 @@ class COMXAudioCodecOMX
 | 
	
		
			
				|  |  | -   bool m_bOpenedCodec;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   int     m_channels;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+  CAEChannelInfo m_channelLayout;
 | 
	
		
			
				|  |  | -   bool m_bFirstFrame;
 | 
	
		
			
				|  |  | -   bool m_bGotFrame;
 | 
	
		
			
				|  |  | -   bool m_bNoConcatenate;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -index a4c11777..d3348ec 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -@@ -567,13 +567,13 @@ bool OMXPlayerAudio::OpenDecoder()
 | 
	
		
			
				|  |  | -   /* GetDataFormat is setting up evrything */
 | 
	
		
			
				|  |  | -   m_format.m_dataFormat = GetDataFormat(m_hints);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  uint64_t channelMap = 0;
 | 
	
		
			
				|  |  | -+  CAEChannelInfo channelMap;
 | 
	
		
			
				|  |  | -   if (m_pAudioCodec && !m_passthrough)
 | 
	
		
			
				|  |  | -     channelMap = m_pAudioCodec->GetChannelMap();
 | 
	
		
			
				|  |  | -   else if (m_passthrough)
 | 
	
		
			
				|  |  | -     // we just want to get the channel count right to stop OMXAudio.cpp rejecting stream
 | 
	
		
			
				|  |  | -     // the actual layout is not used
 | 
	
		
			
				|  |  | --    channelMap = (1<<m_nChannels)-1;
 | 
	
		
			
				|  |  | -+    channelMap = AE_CH_LAYOUT_5_1;
 | 
	
		
			
				|  |  | -   bool bAudioRenderOpen = m_omxAudio.Initialize(m_format, m_av_clock, m_hints, channelMap, m_passthrough, m_hw_decode);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_codec_name = "";
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/PCMRemap.cpp b/xbmc/cores/omxplayer/PCMRemap.cpp
 | 
	
		
			
				|  |  | -deleted file mode 100644
 | 
	
		
			
				|  |  | -index f8acfcc..0000000
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/PCMRemap.cpp
 | 
	
		
			
				|  |  | -+++ /dev/null
 | 
	
		
			
				|  |  | -@@ -1,813 +0,0 @@
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | -- *      Copyright (C) 2005-2010 Team XBMC
 | 
	
		
			
				|  |  | -- *      http://xbmc.org
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -- *  any later version.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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 XBMC; see the file COPYING.  If not, write to
 | 
	
		
			
				|  |  | -- *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
	
		
			
				|  |  | -- *  http://www.gnu.org/copyleft/gpl.html
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#ifndef __STDC_LIMIT_MACROS
 | 
	
		
			
				|  |  | --#define __STDC_LIMIT_MACROS
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#include <cstdlib>
 | 
	
		
			
				|  |  | --#include <string.h>
 | 
	
		
			
				|  |  | --#include <stdio.h>
 | 
	
		
			
				|  |  | --#include <math.h>
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --//#include "MathUtils.h"
 | 
	
		
			
				|  |  | --#include "PCMRemap.h"
 | 
	
		
			
				|  |  | --#include "utils/log.h"
 | 
	
		
			
				|  |  | --#include "utils/StringUtils.h"
 | 
	
		
			
				|  |  | --#include "settings/Settings.h"
 | 
	
		
			
				|  |  | --#include "settings/AdvancedSettings.h"
 | 
	
		
			
				|  |  | --#ifdef _WIN32
 | 
	
		
			
				|  |  | --#include "../win32/PlatformDefs.h"
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --static enum PCMChannels PCMLayoutMap[PCM_MAX_LAYOUT][PCM_MAX_CH + 1] =
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  /* 2.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 2.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 3.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 3.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_LOW_FREQUENCY, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 4.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 4.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 5.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 5.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 7.0 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_INVALID},
 | 
	
		
			
				|  |  | --  /* 7.1 */ {PCM_FRONT_LEFT, PCM_FRONT_RIGHT, PCM_FRONT_CENTER, PCM_SIDE_LEFT, PCM_SIDE_RIGHT, PCM_BACK_LEFT, PCM_BACK_RIGHT, PCM_LOW_FREQUENCY, PCM_INVALID}
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | --  map missing output into channel @ volume level
 | 
	
		
			
				|  |  | --  the order of this table is important, mix tables can not depend on channels that have not been defined yet
 | 
	
		
			
				|  |  | --  eg, FC can only be mixed into FL, FR as they are the only channels that have been defined
 | 
	
		
			
				|  |  | --*/
 | 
	
		
			
				|  |  | --#define PCM_MAX_MIX 3
 | 
	
		
			
				|  |  | --static struct PCMMapInfo PCMDownmixTable[PCM_MAX_CH][PCM_MAX_MIX] =
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  /* PCM_FRONT_LEFT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_FRONT_RIGHT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_FRONT_CENTER */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_LEFT_OF_CENTER , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_FRONT_RIGHT_OF_CENTER, 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_LOW_FREQUENCY */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    /*
 | 
	
		
			
				|  |  | --      A/52B 7.8 paragraph 2 recomends +10db
 | 
	
		
			
				|  |  | --      but due to horrible clipping when normalize
 | 
	
		
			
				|  |  | --      is disabled we set this to 1.0
 | 
	
		
			
				|  |  | --    */
 | 
	
		
			
				|  |  | --    {PCM_FRONT_LEFT           , 1.0},//3.5},
 | 
	
		
			
				|  |  | --    {PCM_FRONT_RIGHT          , 1.0},//3.5},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_BACK_LEFT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_LEFT           , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_BACK_RIGHT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_RIGHT          , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_FRONT_LEFT_OF_CENTER */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_LEFT           , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_FRONT_CENTER         , 1.0, true},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_FRONT_RIGHT_OF_CENTER */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_RIGHT          , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_FRONT_CENTER         , 1.0, true},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_BACK_CENTER */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_BACK_LEFT            , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_BACK_RIGHT           , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_SIDE_LEFT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_LEFT           , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_BACK_LEFT            , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_SIDE_RIGHT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_RIGHT          , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_BACK_RIGHT           , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_TOP_FRONT_LEFT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_LEFT           , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_TOP_FRONT_RIGHT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_FRONT_RIGHT          , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_TOP_FRONT_CENTER */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_TOP_FRONT_LEFT       , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_TOP_FRONT_RIGHT      , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_TOP_CENTER */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_TOP_FRONT_LEFT       , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_TOP_FRONT_RIGHT      , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_TOP_BACK_LEFT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_BACK_LEFT            , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_TOP_BACK_RIGHT */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_BACK_RIGHT           , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  },
 | 
	
		
			
				|  |  | --  /* PCM_TOP_BACK_CENTER */
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    {PCM_TOP_BACK_LEFT        , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_TOP_BACK_RIGHT       , 1.0},
 | 
	
		
			
				|  |  | --    {PCM_INVALID}
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CPCMRemap::CPCMRemap() :
 | 
	
		
			
				|  |  | --  m_inSet       (false),
 | 
	
		
			
				|  |  | --  m_outSet      (false),
 | 
	
		
			
				|  |  | --  m_inChannels  (0),
 | 
	
		
			
				|  |  | --  m_outChannels (0),
 | 
	
		
			
				|  |  | --  m_inSampleSize(0),
 | 
	
		
			
				|  |  | --  m_ignoreLayout(false),
 | 
	
		
			
				|  |  | --  m_buf(NULL),
 | 
	
		
			
				|  |  | --  m_bufsize(0),
 | 
	
		
			
				|  |  | --  m_attenuation (1.0),
 | 
	
		
			
				|  |  | --  m_attenuationInc(0.0),
 | 
	
		
			
				|  |  | --  m_attenuationMin(1.0),
 | 
	
		
			
				|  |  | --  m_sampleRate  (48000.0), //safe default
 | 
	
		
			
				|  |  | --  m_holdCounter (0),
 | 
	
		
			
				|  |  | --  m_limiterEnabled(false)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  Dispose();
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --CPCMRemap::~CPCMRemap()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  Dispose();
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::Dispose()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  free(m_buf);
 | 
	
		
			
				|  |  | --  m_buf = NULL;
 | 
	
		
			
				|  |  | --  m_bufsize = 0;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/* resolves the channels recursively and returns the new index of tablePtr */
 | 
	
		
			
				|  |  | --struct PCMMapInfo* CPCMRemap::ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  if (channel == PCM_INVALID) return tablePtr;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* if its a 1 to 1 mapping, return */
 | 
	
		
			
				|  |  | --  if (m_useable[channel])
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    tablePtr->channel = channel;
 | 
	
		
			
				|  |  | --    tablePtr->level   = level;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    ++tablePtr;
 | 
	
		
			
				|  |  | --    tablePtr->channel = PCM_INVALID;
 | 
	
		
			
				|  |  | --    return tablePtr;
 | 
	
		
			
				|  |  | --  } else
 | 
	
		
			
				|  |  | --    if (ifExists)
 | 
	
		
			
				|  |  | --      level /= 2;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  struct PCMMapInfo *info;
 | 
	
		
			
				|  |  | --  std::vector<enum PCMChannels>::iterator itt;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  for(info = PCMDownmixTable[channel]; info->channel != PCM_INVALID; ++info)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    /* make sure we are not about to recurse into ourself */
 | 
	
		
			
				|  |  | --    bool found = false;
 | 
	
		
			
				|  |  | --    for(itt = path.begin(); itt != path.end(); ++itt)
 | 
	
		
			
				|  |  | --      if (*itt == info->channel)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        found = true;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (found)
 | 
	
		
			
				|  |  | --      continue;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    path.push_back(channel);
 | 
	
		
			
				|  |  | --    float  l = (info->level * (level / 100)) * 100;
 | 
	
		
			
				|  |  | --    tablePtr = ResolveChannel(info->channel, l, info->ifExists, path, tablePtr);
 | 
	
		
			
				|  |  | --    path.pop_back();
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return tablePtr;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | --  Builds a lookup table without extra adjustments, useful if we simply
 | 
	
		
			
				|  |  | --  want to find out which channels are active.
 | 
	
		
			
				|  |  | --  For final adjustments, BuildMap() is used.
 | 
	
		
			
				|  |  | --*/
 | 
	
		
			
				|  |  | --void CPCMRemap::ResolveChannels()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  unsigned int in_ch, out_ch;
 | 
	
		
			
				|  |  | --  bool hasSide = false;
 | 
	
		
			
				|  |  | --  bool hasBack = false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  memset(m_useable, 0, sizeof(m_useable));
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (!m_outSet)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    /* Output format is not known yet, assume the full configured map.
 | 
	
		
			
				|  |  | --     * Note that m_ignoreLayout-using callers normally ignore the result of
 | 
	
		
			
				|  |  | --     * this function when !m_outSet, when it is called only for an advice for
 | 
	
		
			
				|  |  | --     * the caller of SetInputFormat about the best possible output map, and
 | 
	
		
			
				|  |  | --     * they can still set their output format arbitrarily in their call to
 | 
	
		
			
				|  |  | --     * SetOutputFormat. */
 | 
	
		
			
				|  |  | --    for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
 | 
	
		
			
				|  |  | --         m_useable[*chan] = true;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else if (m_ignoreLayout)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
 | 
	
		
			
				|  |  | --      m_useable[m_outMap[out_ch]] = true;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    /* figure out what channels we have and can use */
 | 
	
		
			
				|  |  | --    for(enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
 | 
	
		
			
				|  |  | --        if (m_outMap[out_ch] == *chan)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          m_useable[*chan] = true;
 | 
	
		
			
				|  |  | --          break;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* force mono audio to front left and front right */
 | 
	
		
			
				|  |  | --  if (!m_ignoreLayout && m_inChannels == 1 && m_inMap[0] == PCM_FRONT_CENTER
 | 
	
		
			
				|  |  | --      && m_useable[PCM_FRONT_LEFT] && m_useable[PCM_FRONT_RIGHT])
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "CPCMRemap: Mapping mono audio to front left and front right");
 | 
	
		
			
				|  |  | --    m_useable[PCM_FRONT_CENTER] = false;
 | 
	
		
			
				|  |  | --    m_useable[PCM_FRONT_LEFT_OF_CENTER] = false;
 | 
	
		
			
				|  |  | --    m_useable[PCM_FRONT_RIGHT_OF_CENTER] = false;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* see if our input has side/back channels */
 | 
	
		
			
				|  |  | --  for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
 | 
	
		
			
				|  |  | --    switch(m_inMap[in_ch])
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      case PCM_SIDE_LEFT:
 | 
	
		
			
				|  |  | --      case PCM_SIDE_RIGHT:
 | 
	
		
			
				|  |  | --        hasSide = true;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      case PCM_BACK_LEFT:
 | 
	
		
			
				|  |  | --      case PCM_BACK_RIGHT:
 | 
	
		
			
				|  |  | --        hasBack = true;
 | 
	
		
			
				|  |  | --        break;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      default:;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* if our input has side, and not back channels, and our output doesnt have side channels */
 | 
	
		
			
				|  |  | --  if (hasSide && !hasBack && (!m_useable[PCM_SIDE_LEFT] || !m_useable[PCM_SIDE_RIGHT]))
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "CPCMRemap: Forcing side channel map to back channels");
 | 
	
		
			
				|  |  | --    for(in_ch = 0; in_ch < m_inChannels; ++in_ch)
 | 
	
		
			
				|  |  | --           if (m_inMap[in_ch] == PCM_SIDE_LEFT ) m_inMap[in_ch] = PCM_BACK_LEFT;
 | 
	
		
			
				|  |  | --      else if (m_inMap[in_ch] == PCM_SIDE_RIGHT) m_inMap[in_ch] = PCM_BACK_RIGHT;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* resolve all the channels */
 | 
	
		
			
				|  |  | --  struct PCMMapInfo table[PCM_MAX_CH + 1], *info, *dst;
 | 
	
		
			
				|  |  | --  std::vector<enum PCMChannels> path;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  for (int i = 0; i < PCM_MAX_CH + 1; i++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    for (int j = 0; j < PCM_MAX_CH + 1; j++)
 | 
	
		
			
				|  |  | --      m_lookupMap[i][j].channel = PCM_INVALID;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  memset(m_counts, 0, sizeof(m_counts));
 | 
	
		
			
				|  |  | --  for(in_ch = 0; in_ch < m_inChannels; ++in_ch) {
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    for (int i = 0; i < PCM_MAX_CH + 1; i++)
 | 
	
		
			
				|  |  | --      table[i].channel = PCM_INVALID;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    ResolveChannel(m_inMap[in_ch], 1.0f, false, path, table);
 | 
	
		
			
				|  |  | --    for(info = table; info->channel != PCM_INVALID; ++info)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      /* find the end of the table */
 | 
	
		
			
				|  |  | --      for(dst = m_lookupMap[info->channel]; dst->channel != PCM_INVALID; ++dst);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      /* append it to the table and set its input offset */
 | 
	
		
			
				|  |  | --      dst->channel   = m_inMap[in_ch];
 | 
	
		
			
				|  |  | --      dst->in_offset = in_ch * 2;
 | 
	
		
			
				|  |  | --      dst->level     = info->level;
 | 
	
		
			
				|  |  | --      m_counts[dst->channel]++;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | --  builds a lookup table to convert from the input mapping to the output
 | 
	
		
			
				|  |  | --  mapping, this decreases the amount of work per sample to remap it.
 | 
	
		
			
				|  |  | --*/
 | 
	
		
			
				|  |  | --void CPCMRemap::BuildMap()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  struct PCMMapInfo *dst;
 | 
	
		
			
				|  |  | --  unsigned int out_ch;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (!m_inSet || !m_outSet) return;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_inStride  = m_inSampleSize * m_inChannels ;
 | 
	
		
			
				|  |  | --  m_outStride = m_inSampleSize * m_outChannels;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* see if we need to normalize the levels */
 | 
	
		
			
				|  |  | --  bool dontnormalize = !CSettings::Get().GetBool("audiooutput.normalizelevels");
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "CPCMRemap: Downmix normalization is %s", (dontnormalize ? "disabled" : "enabled"));
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  ResolveChannels();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* convert the levels into RMS values */
 | 
	
		
			
				|  |  | --  float loudest    = 0.0;
 | 
	
		
			
				|  |  | --  bool  hasLoudest = false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    float scale = 0;
 | 
	
		
			
				|  |  | --    int count = 0;
 | 
	
		
			
				|  |  | --    for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      dst->copy  = false;
 | 
	
		
			
				|  |  | --      dst->level = dst->level / sqrt((float)m_counts[dst->channel]);
 | 
	
		
			
				|  |  | --      scale     += dst->level;
 | 
	
		
			
				|  |  | --      ++count;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    /* if there is only 1 channel to mix, and the level is 1.0, then just copy the channel */
 | 
	
		
			
				|  |  | --    dst = m_lookupMap[m_outMap[out_ch]];
 | 
	
		
			
				|  |  | --    if (count == 1 && dst->level > 0.99 && dst->level < 1.01)
 | 
	
		
			
				|  |  | --      dst->copy = true;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    /* normalize the levels if it is turned on */
 | 
	
		
			
				|  |  | --    if (!dontnormalize)
 | 
	
		
			
				|  |  | --      for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        dst->level /= scale;
 | 
	
		
			
				|  |  | --        /* find the loudest output level we have that is not 1-1 */
 | 
	
		
			
				|  |  | --        if (dst->level < 1.0 && loudest < dst->level)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          loudest    = dst->level;
 | 
	
		
			
				|  |  | --          hasLoudest = true;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* adjust the channels that are too loud */
 | 
	
		
			
				|  |  | --  for(out_ch = 0; out_ch < m_outChannels; ++out_ch)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CStdString s = "", f;
 | 
	
		
			
				|  |  | --    for(dst = m_lookupMap[m_outMap[out_ch]]; dst->channel != PCM_INVALID; ++dst)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      if (hasLoudest && dst->copy)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        dst->level = loudest;
 | 
	
		
			
				|  |  | --        dst->copy  = false;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      f = StringUtils::Format("%s(%f%s) ",  PCMChannelStr(dst->channel).c_str(), dst->level, dst->copy ? "*" : "");
 | 
	
		
			
				|  |  | --      s += f;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "CPCMRemap: %s = %s\n", PCMChannelStr(m_outMap[out_ch]).c_str(), s.c_str());
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::DumpMap(CStdString info, unsigned int channels, enum PCMChannels *channelMap)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  if (channelMap == NULL)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    CLog::Log(LOGINFO, "CPCMRemap: %s channel map: NULL", info.c_str());
 | 
	
		
			
				|  |  | --    return;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  CStdString mapping;
 | 
	
		
			
				|  |  | --  for(unsigned int i = 0; i < channels; ++i)
 | 
	
		
			
				|  |  | --    mapping += ((i == 0) ? "" : ",") + PCMChannelStr(channelMap[i]);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  CLog::Log(LOGINFO, "CPCMRemap: %s channel map: %s\n", info.c_str(), mapping.c_str());
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::Reset()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  m_inSet  = false;
 | 
	
		
			
				|  |  | --  m_outSet = false;
 | 
	
		
			
				|  |  | --  Dispose();
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/* sets the input format, and returns the requested channel layout */
 | 
	
		
			
				|  |  | --enum PCMChannels *CPCMRemap::SetInputFormat(unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate, PCMLayout layout)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  m_inChannels   = channels;
 | 
	
		
			
				|  |  | --  m_inSampleSize = sampleSize;
 | 
	
		
			
				|  |  | --  m_sampleRate   = sampleRate;
 | 
	
		
			
				|  |  | --  m_inSet        = channelMap != NULL;
 | 
	
		
			
				|  |  | --  if (channelMap)
 | 
	
		
			
				|  |  | --    memcpy(m_inMap, channelMap, sizeof(enum PCMChannels) * channels);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* get the audio layout, and count the channels in it */
 | 
	
		
			
				|  |  | --  m_channelLayout  = layout;
 | 
	
		
			
				|  |  | --  if (m_channelLayout >= PCM_MAX_LAYOUT) m_channelLayout = PCM_LAYOUT_2_0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  DumpMap("I", channels, channelMap);
 | 
	
		
			
				|  |  | --  BuildMap();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  /* now remove the empty channels from PCMLayoutMap;
 | 
	
		
			
				|  |  | --   * we don't perform upmixing so we want the minimum amount of those */
 | 
	
		
			
				|  |  | --  if (channelMap) {
 | 
	
		
			
				|  |  | --    if (!m_outSet)
 | 
	
		
			
				|  |  | --      ResolveChannels(); /* Do basic channel resolving to find out the empty channels;
 | 
	
		
			
				|  |  | --                          * If m_outSet == true, this was done already by BuildMap() above */
 | 
	
		
			
				|  |  | --    int i = 0;
 | 
	
		
			
				|  |  | --    for (enum PCMChannels *chan = PCMLayoutMap[m_channelLayout]; *chan != PCM_INVALID; ++chan)
 | 
	
		
			
				|  |  | --      if (m_lookupMap[*chan][0].channel != PCM_INVALID) {
 | 
	
		
			
				|  |  | --        /* something is mapped here, so add the channel */
 | 
	
		
			
				|  |  | --        m_layoutMap[i++] = *chan;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    m_layoutMap[i] = PCM_INVALID;
 | 
	
		
			
				|  |  | --  } else
 | 
	
		
			
				|  |  | --    memcpy(m_layoutMap, PCMLayoutMap[m_channelLayout], sizeof(PCMLayoutMap[m_channelLayout]));
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_attenuation = 1.0;
 | 
	
		
			
				|  |  | --  m_attenuationInc = 1.0;
 | 
	
		
			
				|  |  | --  m_holdCounter = 0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return m_layoutMap;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/* sets the output format supported by the audio renderer */
 | 
	
		
			
				|  |  | --void CPCMRemap::SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout/* = false */)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  m_outChannels   = channels;
 | 
	
		
			
				|  |  | --  m_outSet        = channelMap != NULL;
 | 
	
		
			
				|  |  | --  m_ignoreLayout  = ignoreLayout;
 | 
	
		
			
				|  |  | --  if (channelMap)
 | 
	
		
			
				|  |  | --    memcpy(m_outMap, channelMap, sizeof(enum PCMChannels) * channels);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  DumpMap("O", channels, channelMap);
 | 
	
		
			
				|  |  | --  BuildMap();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_attenuation = 1.0;
 | 
	
		
			
				|  |  | --  m_attenuationInc = 1.0;
 | 
	
		
			
				|  |  | --  m_holdCounter = 0;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#if 0
 | 
	
		
			
				|  |  | --void CPCMRemap::Remap(void *data, void *out, unsigned int samples, long drc)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  float gain = 1.0f;
 | 
	
		
			
				|  |  | --  if (drc > 0)
 | 
	
		
			
				|  |  | --    gain = pow(10.0f, (float)drc / 2000.0f);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  Remap(data, out, samples, gain);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/* remap the supplied data into out, which must be pre-allocated */
 | 
	
		
			
				|  |  | --void CPCMRemap::Remap(void *data, void *out, unsigned int samples, float gain /*= 1.0f*/)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  CheckBufferSize(samples * m_outChannels * sizeof(float));
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  //set output buffer to 0
 | 
	
		
			
				|  |  | --  memset(out, 0, samples * m_outChannels * m_inSampleSize);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  //set intermediate buffer to 0
 | 
	
		
			
				|  |  | --  memset(m_buf, 0, m_bufsize);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  ProcessInput(data, out, samples, gain);
 | 
	
		
			
				|  |  | --  AddGain(m_buf, samples * m_outChannels, gain);
 | 
	
		
			
				|  |  | --  ProcessLimiter(samples, gain);
 | 
	
		
			
				|  |  | --  ProcessOutput(out, samples, gain);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::CheckBufferSize(int size)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  if (m_bufsize < size)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_bufsize = size;
 | 
	
		
			
				|  |  | --    m_buf = (float*)realloc(m_buf, m_bufsize);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::ProcessInput(void* data, void* out, unsigned int samples, float gain)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  for (unsigned int ch = 0; ch < m_outChannels; ch++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
 | 
	
		
			
				|  |  | --    if (info->channel == PCM_INVALID)
 | 
	
		
			
				|  |  | --      continue;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (info->copy && gain == 1.0f) //do direct copy
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      uint8_t* src = (uint8_t*)data + info->in_offset;
 | 
	
		
			
				|  |  | --      uint8_t* dst = (uint8_t*)out  + ch * m_inSampleSize;
 | 
	
		
			
				|  |  | --      uint8_t* dstend = dst + samples * m_outStride;
 | 
	
		
			
				|  |  | --      while (dst != dstend)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        *(int16_t*)dst = *(int16_t*)src;
 | 
	
		
			
				|  |  | --        src += m_inStride;
 | 
	
		
			
				|  |  | --        dst += m_outStride;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else //needs some volume change or mixing, put into intermediate buffer
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      for(; info->channel != PCM_INVALID; info++)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        uint8_t* src = (uint8_t*)data + info->in_offset;
 | 
	
		
			
				|  |  | --        float*   dst = m_buf + ch;
 | 
	
		
			
				|  |  | --        float*   dstend = dst + samples * m_outChannels;
 | 
	
		
			
				|  |  | --        while (dst != dstend)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          *dst += (float)(*(int16_t*)src) * info->level;
 | 
	
		
			
				|  |  | --          src += m_inStride;
 | 
	
		
			
				|  |  | --          dst += m_outChannels;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::AddGain(float* buf, unsigned int samples, float gain)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  if (gain != 1.0f) //needs a gain change
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    float* ptr = m_buf;
 | 
	
		
			
				|  |  | --    float* end = m_buf + samples;
 | 
	
		
			
				|  |  | --    while (ptr != end)
 | 
	
		
			
				|  |  | --      *(ptr++) *= gain;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::ProcessLimiter(unsigned int samples, float gain)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  //check total gain for each output channel
 | 
	
		
			
				|  |  | --  float highestgain = 1.0f;
 | 
	
		
			
				|  |  | --  for (unsigned int ch = 0; ch < m_outChannels; ch++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
 | 
	
		
			
				|  |  | --    if (info->channel == PCM_INVALID)
 | 
	
		
			
				|  |  | --      continue;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    float chgain = 0.0f;
 | 
	
		
			
				|  |  | --    for(; info->channel != PCM_INVALID; info++)
 | 
	
		
			
				|  |  | --      chgain += info->level * gain;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (chgain > highestgain)
 | 
	
		
			
				|  |  | --      highestgain = chgain;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  m_attenuationMin = 1.0f;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  //if one of the channels can clip, enable a limiter
 | 
	
		
			
				|  |  | --  if (highestgain > 1.0001f)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_attenuationMin = m_attenuation;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (!m_limiterEnabled)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, enabling limiter", highestgain);
 | 
	
		
			
				|  |  | --      m_limiterEnabled = true;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    for (unsigned int i = 0; i < samples; i++)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      //for each collection of samples, get the highest absolute value
 | 
	
		
			
				|  |  | --      float maxAbs = 0.0f;
 | 
	
		
			
				|  |  | --      for (unsigned int outch = 0; outch < m_outChannels; outch++)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        float absval = fabs(m_buf[i * m_outChannels + outch]) / 32768.0f;
 | 
	
		
			
				|  |  | --        if (maxAbs < absval)
 | 
	
		
			
				|  |  | --          maxAbs = absval;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      //if attenuatedAbs is higher than 1.0f, audio is clipping
 | 
	
		
			
				|  |  | --      float attenuatedAbs = maxAbs * m_attenuation;
 | 
	
		
			
				|  |  | --      if (attenuatedAbs > 1.0f)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        //set m_attenuation so that m_attenuation * sample is the maximum output value
 | 
	
		
			
				|  |  | --        m_attenuation = 1.0f / maxAbs;
 | 
	
		
			
				|  |  | --        if (m_attenuation < m_attenuationMin)
 | 
	
		
			
				|  |  | --          m_attenuationMin = m_attenuation;
 | 
	
		
			
				|  |  | --        //value to add to m_attenuation to make it 1.0f
 | 
	
		
			
				|  |  | --        m_attenuationInc = 1.0f - m_attenuation;
 | 
	
		
			
				|  |  | --        //amount of samples to hold m_attenuation
 | 
	
		
			
				|  |  | --        m_holdCounter = MathUtils::round_int(m_sampleRate * g_advancedSettings.m_limiterHold);
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --      else if (m_attenuation < 1.0f && attenuatedAbs > 0.95f)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        //if we're attenuating and we get within 5% of clipping, hold m_attenuation
 | 
	
		
			
				|  |  | --        m_attenuationInc = 1.0f - m_attenuation;
 | 
	
		
			
				|  |  | --        m_holdCounter = MathUtils::round_int(m_sampleRate * g_advancedSettings.m_limiterHold);
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      //apply attenuation
 | 
	
		
			
				|  |  | --      for (unsigned int outch = 0; outch < m_outChannels; outch++)
 | 
	
		
			
				|  |  | --        m_buf[i * m_outChannels + outch] *= m_attenuation;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      if (m_holdCounter)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        //hold m_attenuation
 | 
	
		
			
				|  |  | --        m_holdCounter--;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --      else if (m_attenuationInc > 0.0f)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        //move m_attenuation to 1.0 in g_advancedSettings.m_limiterRelease seconds
 | 
	
		
			
				|  |  | --        m_attenuation += m_attenuationInc / m_sampleRate / g_advancedSettings.m_limiterRelease;
 | 
	
		
			
				|  |  | --        if (m_attenuation > 1.0f)
 | 
	
		
			
				|  |  | --        {
 | 
	
		
			
				|  |  | --          m_attenuation = 1.0f;
 | 
	
		
			
				|  |  | --          m_attenuationInc = 0.0f;
 | 
	
		
			
				|  |  | --        }
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if (m_limiterEnabled)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "CPCMRemap:: max gain: %f, disabling limiter", highestgain);
 | 
	
		
			
				|  |  | --      m_limiterEnabled = false;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    //reset the limiter
 | 
	
		
			
				|  |  | --    m_attenuation = 1.0f;
 | 
	
		
			
				|  |  | --    m_attenuationInc = 0.0f;
 | 
	
		
			
				|  |  | --    m_holdCounter = 0;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::ProcessOutput(void* out, unsigned int samples, float gain)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  //copy from intermediate buffer to output
 | 
	
		
			
				|  |  | --  for (unsigned int ch = 0; ch < m_outChannels; ch++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
 | 
	
		
			
				|  |  | --    if (info->channel == PCM_INVALID)
 | 
	
		
			
				|  |  | --      continue;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (!info->copy || gain != 1.0f)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      float* src = m_buf + ch;
 | 
	
		
			
				|  |  | --      uint8_t* dst = (uint8_t*)out + ch * m_inSampleSize;
 | 
	
		
			
				|  |  | --      uint8_t* dstend = dst + samples * m_outStride;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      while(dst != dstend)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        *(int16_t*)dst = MathUtils::round_int(std::min(std::max(*src, (float)INT16_MIN), (float)INT16_MAX));
 | 
	
		
			
				|  |  | --        src += m_outChannels;
 | 
	
		
			
				|  |  | --        dst += m_outStride;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --bool CPCMRemap::CanRemap()
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return (m_inSet && m_outSet);
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --int CPCMRemap::InBytesToFrames(int bytes)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return bytes / m_inSampleSize / m_inChannels;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --int CPCMRemap::FramesToOutBytes(int frames)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return frames * m_inSampleSize * m_outChannels;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --int CPCMRemap::FramesToInBytes(int frames)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  return frames * m_inSampleSize * m_inChannels;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --CStdString CPCMRemap::PCMChannelStr(enum PCMChannels ename)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  const char* PCMChannelName[] =
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    "FL",
 | 
	
		
			
				|  |  | --    "FR",
 | 
	
		
			
				|  |  | --    "CE",
 | 
	
		
			
				|  |  | --    "LFE",
 | 
	
		
			
				|  |  | --    "BL",
 | 
	
		
			
				|  |  | --    "BR",
 | 
	
		
			
				|  |  | --    "FLOC",
 | 
	
		
			
				|  |  | --    "FROC",
 | 
	
		
			
				|  |  | --    "BC",
 | 
	
		
			
				|  |  | --    "SL",
 | 
	
		
			
				|  |  | --    "SR",
 | 
	
		
			
				|  |  | --    "TFL",
 | 
	
		
			
				|  |  | --    "TFR",
 | 
	
		
			
				|  |  | --    "TFC",
 | 
	
		
			
				|  |  | --    "TC",
 | 
	
		
			
				|  |  | --    "TBL",
 | 
	
		
			
				|  |  | --    "TBR",
 | 
	
		
			
				|  |  | --    "TBC"
 | 
	
		
			
				|  |  | --  };
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  int namepos = (int)ename;
 | 
	
		
			
				|  |  | --  CStdString namestr;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (namepos < 0 || namepos >= (int)(sizeof(PCMChannelName) / sizeof(const char*)))
 | 
	
		
			
				|  |  | --    namestr = StringUtils::Format("UNKNOWN CHANNEL:%i", namepos);
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    namestr = PCMChannelName[namepos];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return namestr;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --#if 0
 | 
	
		
			
				|  |  | --CStdString CPCMRemap::PCMLayoutStr(enum PCMLayout ename)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  const char* PCMLayoutName[] =
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    "2.0",
 | 
	
		
			
				|  |  | --    "2.1",
 | 
	
		
			
				|  |  | --    "3.0",
 | 
	
		
			
				|  |  | --    "3.1",
 | 
	
		
			
				|  |  | --    "4.0",
 | 
	
		
			
				|  |  | --    "4.1",
 | 
	
		
			
				|  |  | --    "5.0",
 | 
	
		
			
				|  |  | --    "5.1",
 | 
	
		
			
				|  |  | --    "7.0",
 | 
	
		
			
				|  |  | --    "7.1"
 | 
	
		
			
				|  |  | --  };
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  int namepos = (int)ename;
 | 
	
		
			
				|  |  | --  CStdString namestr;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (namepos < 0 || namepos >= (int)(sizeof(PCMLayoutName) / sizeof(const char*)))
 | 
	
		
			
				|  |  | --    namestr.Format("UNKNOWN LAYOUT:%i", namepos);
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    namestr = PCMLayoutName[namepos];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  return namestr;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --void CPCMRemap::GetDownmixMatrix(float *downmix)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  for (int i=0; i<8*8; i++)
 | 
	
		
			
				|  |  | --    downmix[i] = 0.0f;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  for (unsigned int ch = 0; ch < m_outChannels; ch++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    struct PCMMapInfo *info = m_lookupMap[m_outMap[ch]];
 | 
	
		
			
				|  |  | --    if (info->channel == PCM_INVALID)
 | 
	
		
			
				|  |  | --      continue;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    for(; info->channel != PCM_INVALID; info++)
 | 
	
		
			
				|  |  | --      downmix[8*ch + (info->in_offset>>1)] = info->level;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/PCMRemap.h b/xbmc/cores/omxplayer/PCMRemap.h
 | 
	
		
			
				|  |  | -deleted file mode 100644
 | 
	
		
			
				|  |  | -index a273cd1..0000000
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/PCMRemap.h
 | 
	
		
			
				|  |  | -+++ /dev/null
 | 
	
		
			
				|  |  | -@@ -1,151 +0,0 @@
 | 
	
		
			
				|  |  | --#ifndef __PCM_REMAP__H__
 | 
	
		
			
				|  |  | --#define __PCM_REMAP__H__
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --/*
 | 
	
		
			
				|  |  | -- *      Copyright (C) 2005-2010 Team XBMC
 | 
	
		
			
				|  |  | -- *      http://xbmc.org
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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, or (at your option)
 | 
	
		
			
				|  |  | -- *  any later version.
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- *  This Program 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 XBMC; see the file COPYING.  If not, write to
 | 
	
		
			
				|  |  | -- *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
	
		
			
				|  |  | -- *  http://www.gnu.org/copyleft/gpl.html
 | 
	
		
			
				|  |  | -- *
 | 
	
		
			
				|  |  | -- */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#include <stdint.h>
 | 
	
		
			
				|  |  | --#include <vector>
 | 
	
		
			
				|  |  | --#include "utils/StdString.h"
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#define PCM_MAX_CH 18
 | 
	
		
			
				|  |  | --enum PCMChannels
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  PCM_INVALID = -1,
 | 
	
		
			
				|  |  | --  PCM_FRONT_LEFT,
 | 
	
		
			
				|  |  | --  PCM_FRONT_RIGHT,
 | 
	
		
			
				|  |  | --  PCM_FRONT_CENTER,
 | 
	
		
			
				|  |  | --  PCM_LOW_FREQUENCY,
 | 
	
		
			
				|  |  | --  PCM_BACK_LEFT,
 | 
	
		
			
				|  |  | --  PCM_BACK_RIGHT,
 | 
	
		
			
				|  |  | --  PCM_FRONT_LEFT_OF_CENTER,
 | 
	
		
			
				|  |  | --  PCM_FRONT_RIGHT_OF_CENTER,
 | 
	
		
			
				|  |  | --  PCM_BACK_CENTER,
 | 
	
		
			
				|  |  | --  PCM_SIDE_LEFT,
 | 
	
		
			
				|  |  | --  PCM_SIDE_RIGHT,
 | 
	
		
			
				|  |  | --  PCM_TOP_FRONT_LEFT,
 | 
	
		
			
				|  |  | --  PCM_TOP_FRONT_RIGHT,
 | 
	
		
			
				|  |  | --  PCM_TOP_FRONT_CENTER,
 | 
	
		
			
				|  |  | --  PCM_TOP_CENTER,
 | 
	
		
			
				|  |  | --  PCM_TOP_BACK_LEFT,
 | 
	
		
			
				|  |  | --  PCM_TOP_BACK_RIGHT,
 | 
	
		
			
				|  |  | --  PCM_TOP_BACK_CENTER
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#define PCM_MAX_LAYOUT 10
 | 
	
		
			
				|  |  | --enum PCMLayout
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_2_0 = 0,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_2_1,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_3_0,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_3_1,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_4_0,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_4_1,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_5_0,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_5_1,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_7_0,
 | 
	
		
			
				|  |  | --  PCM_LAYOUT_7_1
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --struct PCMMapInfo
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  enum  PCMChannels channel;
 | 
	
		
			
				|  |  | --  float level;
 | 
	
		
			
				|  |  | --  bool  ifExists;
 | 
	
		
			
				|  |  | --  int   in_offset;
 | 
	
		
			
				|  |  | --  bool  copy;
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --//!  Channels remapper class
 | 
	
		
			
				|  |  | --/*!
 | 
	
		
			
				|  |  | --   The usual set-up process:
 | 
	
		
			
				|  |  | --   - user calls SetInputFormat with the input channels information
 | 
	
		
			
				|  |  | --   - SetInputFormat responds with a channelmap corresponding to the speaker
 | 
	
		
			
				|  |  | --     layout that the user has configured, with empty (according to information
 | 
	
		
			
				|  |  | --     calculated from the input channelmap) channels removed
 | 
	
		
			
				|  |  | --   - user uses this information to create the desired output channelmap,
 | 
	
		
			
				|  |  | --     and calls SetOutputFormat to set it (if the channelmap contains channels
 | 
	
		
			
				|  |  | --     that do not exist in the configured speaker layout, they will contain
 | 
	
		
			
				|  |  | --     only silence unless ignoreLayout is true)
 | 
	
		
			
				|  |  | -- */
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --class CPCMRemap
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --protected:
 | 
	
		
			
				|  |  | --  bool               m_inSet, m_outSet;
 | 
	
		
			
				|  |  | --  enum PCMLayout     m_channelLayout;
 | 
	
		
			
				|  |  | --  unsigned int       m_inChannels, m_outChannels;
 | 
	
		
			
				|  |  | --  unsigned int       m_inSampleSize;
 | 
	
		
			
				|  |  | --  enum PCMChannels   m_inMap [PCM_MAX_CH];
 | 
	
		
			
				|  |  | --  enum PCMChannels   m_outMap[PCM_MAX_CH];
 | 
	
		
			
				|  |  | --  enum PCMChannels   m_layoutMap[PCM_MAX_CH + 1];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  bool               m_ignoreLayout;
 | 
	
		
			
				|  |  | --  bool               m_useable  [PCM_MAX_CH];
 | 
	
		
			
				|  |  | --  int                m_inStride, m_outStride;
 | 
	
		
			
				|  |  | --  struct PCMMapInfo  m_lookupMap[PCM_MAX_CH + 1][PCM_MAX_CH + 1];
 | 
	
		
			
				|  |  | --  int                m_counts[PCM_MAX_CH];
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  float*             m_buf;
 | 
	
		
			
				|  |  | --  int                m_bufsize;
 | 
	
		
			
				|  |  | --  float              m_attenuation;
 | 
	
		
			
				|  |  | --  float              m_attenuationInc;
 | 
	
		
			
				|  |  | --  float              m_attenuationMin; //lowest attenuation value during a call of Remap(), used for the codec info
 | 
	
		
			
				|  |  | --  float              m_sampleRate;
 | 
	
		
			
				|  |  | --  unsigned int       m_holdCounter;
 | 
	
		
			
				|  |  | --  bool               m_limiterEnabled;
 | 
	
		
			
				|  |  | --  bool               m_dontnormalize;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  struct PCMMapInfo* ResolveChannel(enum PCMChannels channel, float level, bool ifExists, std::vector<enum PCMChannels> path, struct PCMMapInfo *tablePtr);
 | 
	
		
			
				|  |  | --  void               ResolveChannels(); //!< Partial BuildMap(), just enough to see which output channels are active
 | 
	
		
			
				|  |  | --  void               BuildMap();
 | 
	
		
			
				|  |  | --  void               DumpMap(CStdString info, int unsigned channels, enum PCMChannels *channelMap);
 | 
	
		
			
				|  |  | --  void               Dispose();
 | 
	
		
			
				|  |  | --  CStdString         PCMChannelStr(enum PCMChannels ename);
 | 
	
		
			
				|  |  | --  CStdString         PCMLayoutStr(enum PCMLayout ename);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  void               CheckBufferSize(int size);
 | 
	
		
			
				|  |  | --  void               ProcessInput(void* data, void* out, unsigned int samples, float gain);
 | 
	
		
			
				|  |  | --  void               AddGain(float* buf, unsigned int samples, float gain);
 | 
	
		
			
				|  |  | --  void               ProcessLimiter(unsigned int samples, float gain);
 | 
	
		
			
				|  |  | --  void               ProcessOutput(void* out, unsigned int samples, float gain);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --public:
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  CPCMRemap();
 | 
	
		
			
				|  |  | --  ~CPCMRemap();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  void Reset();
 | 
	
		
			
				|  |  | --  enum PCMChannels *SetInputFormat (unsigned int channels, enum PCMChannels *channelMap, unsigned int sampleSize, unsigned int sampleRate, PCMLayout layout);
 | 
	
		
			
				|  |  | --  void SetOutputFormat(unsigned int channels, enum PCMChannels *channelMap, bool ignoreLayout = false);
 | 
	
		
			
				|  |  | --#if 0
 | 
	
		
			
				|  |  | --  void Remap(void *data, void *out, unsigned int samples, long drc);
 | 
	
		
			
				|  |  | --  void Remap(void *data, void *out, unsigned int samples, float gain = 1.0f);
 | 
	
		
			
				|  |  | --  bool CanRemap();
 | 
	
		
			
				|  |  | --  int  InBytesToFrames (int bytes );
 | 
	
		
			
				|  |  | --  int  FramesToOutBytes(int frames);
 | 
	
		
			
				|  |  | --  int  FramesToInBytes (int frames);
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --  float GetCurrentAttenuation() { return m_attenuationMin; }
 | 
	
		
			
				|  |  | --  void               GetDownmixMatrix(float *downmix);
 | 
	
		
			
				|  |  | --};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From f642e8eac4fb16039ce662a8a170908efd43ebf8 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 10 Apr 2014 17:19:18 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 66/94] [omxplayer] Remove unused framerate functions
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp |  4 +---
 | 
	
		
			
				|  |  | - xbmc/linux/OMXClock.cpp                 | 35 ---------------------------------
 | 
	
		
			
				|  |  | - xbmc/linux/OMXClock.h                   |  4 ----
 | 
	
		
			
				|  |  | - 3 files changed, 1 insertion(+), 42 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index a5620da..019f4b2 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -527,7 +527,7 @@ bool OMXPlayerVideo::OpenDecoder()
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (m_hints.fpsrate && m_hints.fpsscale)
 | 
	
		
			
				|  |  | --    m_fFrameRate = DVD_TIME_BASE / OMXClock::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate);
 | 
	
		
			
				|  |  | -+    m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE * m_hints.fpsscale / m_hints.fpsrate);
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -     m_fFrameRate = 25;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -564,8 +564,6 @@ bool OMXPlayerVideo::OpenDecoder()
 | 
	
		
			
				|  |  | -     sprintf(command, "hdmi_ntsc_freqs %d", bNtscFreq);
 | 
	
		
			
				|  |  | -     CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder fps: %f %s\n", m_fFrameRate, command);
 | 
	
		
			
				|  |  | -     m_DllBcmHost.vc_gencmd(response, sizeof response, command);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    m_av_clock->SetRefreshRate(m_fFrameRate);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // start from assuming all recent frames had valid pts
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/OMXClock.cpp b/xbmc/linux/OMXClock.cpp
 | 
	
		
			
				|  |  | -index bee7bac..c631ab6 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/OMXClock.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/OMXClock.cpp
 | 
	
		
			
				|  |  | -@@ -39,7 +39,6 @@ OMXClock::OMXClock()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_pause       = false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  m_fps = 25.0f;
 | 
	
		
			
				|  |  | -   m_omx_speed = DVD_PLAYSPEED_NORMAL;
 | 
	
		
			
				|  |  | -   m_WaitMask = 0;
 | 
	
		
			
				|  |  | -   m_eState = OMX_TIME_ClockStateStopped;
 | 
	
		
			
				|  |  | -@@ -565,38 +564,4 @@ int64_t OMXClock::CurrentHostFrequency(void)
 | 
	
		
			
				|  |  | -   return( (int64_t)1000000000L );
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --int OMXClock::GetRefreshRate(double* interval)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  if(!interval)
 | 
	
		
			
				|  |  | --    return false;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  *interval = m_fps;
 | 
	
		
			
				|  |  | --  return true;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --double OMXClock::NormalizeFrameduration(double frameduration)
 | 
	
		
			
				|  |  | --{
 | 
	
		
			
				|  |  | --  //if the duration is within 20 microseconds of a common duration, use that
 | 
	
		
			
				|  |  | --  const double durations[] = {DVD_TIME_BASE * 1.001 / 24.0, DVD_TIME_BASE / 24.0, DVD_TIME_BASE / 25.0,
 | 
	
		
			
				|  |  | --                              DVD_TIME_BASE * 1.001 / 30.0, DVD_TIME_BASE / 30.0, DVD_TIME_BASE / 50.0,
 | 
	
		
			
				|  |  | --                              DVD_TIME_BASE * 1.001 / 60.0, DVD_TIME_BASE / 60.0};
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  double lowestdiff = DVD_TIME_BASE;
 | 
	
		
			
				|  |  | --  int    selected   = -1;
 | 
	
		
			
				|  |  | --  for (size_t i = 0; i < sizeof(durations) / sizeof(durations[0]); i++)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    double diff = fabs(frameduration - durations[i]);
 | 
	
		
			
				|  |  | --    if (diff < DVD_MSEC_TO_TIME(0.02) && diff < lowestdiff)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      selected = i;
 | 
	
		
			
				|  |  | --      lowestdiff = diff;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (selected != -1)
 | 
	
		
			
				|  |  | --    return durations[selected];
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    return frameduration;
 | 
	
		
			
				|  |  | --}
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/OMXClock.h b/xbmc/linux/OMXClock.h
 | 
	
		
			
				|  |  | -index f83074a..7bb6d4d 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/OMXClock.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/OMXClock.h
 | 
	
		
			
				|  |  | -@@ -50,7 +50,6 @@ class OMXClock
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   bool              m_pause;
 | 
	
		
			
				|  |  | -   pthread_mutex_t   m_lock;
 | 
	
		
			
				|  |  | --  double            m_fps;
 | 
	
		
			
				|  |  | -   int               m_omx_speed;
 | 
	
		
			
				|  |  | -   OMX_U32           m_WaitMask;
 | 
	
		
			
				|  |  | -   OMX_TIME_CLOCKSTATE   m_eState;
 | 
	
		
			
				|  |  | -@@ -91,9 +90,6 @@ class OMXClock
 | 
	
		
			
				|  |  | -   static int64_t CurrentHostCounter(void);
 | 
	
		
			
				|  |  | -   static int64_t CurrentHostFrequency(void);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  int     GetRefreshRate(double* interval = NULL);
 | 
	
		
			
				|  |  | --  void    SetRefreshRate(double fps) { m_fps = fps; };
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   static double NormalizeFrameduration(double frameduration);
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 652d09aff0c0ed4cab08ab7ebbe0da37118c53ba Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sun, 30 Mar 2014 15:54:34 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 67/94] [omxplayer] Make the sharpness control act as a
 | 
	
		
			
				|  |  | - sharpness control.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This fixes scaling kernel as Mitchell Netravali, and varies sharpness over range B=[5/3,0] C=[-1/3,1/2]
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayer.cpp | 338 +++++++++++++++++++++++++++++++++++++
 | 
	
		
			
				|  |  | - 1 file changed, 338 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayer.cpp b/xbmc/cores/omxplayer/OMXPlayer.cpp
 | 
	
		
			
				|  |  | -index 2515fa1..b09e8e0 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayer.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayer.cpp
 | 
	
		
			
				|  |  | -@@ -1051,6 +1051,334 @@ bool COMXPlayer::IsBetterStream(COMXCurrentStream& current, CDemuxStream* stream
 | 
	
		
			
				|  |  | -   return false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+static void SetSharpness(float sharpness)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  const int16_t mitchells[][32] =
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+      { // B=1.66667 C=-0.33333
 | 
	
		
			
				|  |  | -+         0,  3,  8, 15, 24, 35, 49, 55, 70, 92,100,107,109,113,113,114,114,113,113,109,107,100, 92, 70, 55, 49, 35, 24, 15,  8,  3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.64000 C=-0.32000
 | 
	
		
			
				|  |  | -+         0,  3,  7, 14, 24, 34, 48, 54, 69, 91,100,107,111,114,116,116,116,116,114,111,107,100, 91, 69, 54, 48, 34, 24, 14,  7,  3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.61333 C=-0.30667
 | 
	
		
			
				|  |  | -+         0,  3,  7, 14, 23, 34, 47, 53, 68, 90, 99,107,112,115,118,118,118,118,115,112,107, 99, 90, 68, 53, 47, 34, 23, 14,  7,  3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.58667 C=-0.29333
 | 
	
		
			
				|  |  | -+         0,  2,  7, 14, 22, 33, 46, 52, 67, 89, 99,107,113,117,119,121,121,119,117,113,107, 99, 89, 67, 52, 46, 33, 22, 14,  7,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.56000 C=-0.28000
 | 
	
		
			
				|  |  | -+         0,  2,  7, 13, 22, 32, 45, 51, 66, 88, 98,107,114,119,121,123,123,121,119,114,107, 98, 88, 66, 51, 45, 32, 22, 13,  7,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.53333 C=-0.26667
 | 
	
		
			
				|  |  | -+         0,  2,  7, 12, 21, 31, 44, 50, 65, 87, 98,108,114,120,123,125,125,123,120,114,108, 98, 87, 65, 50, 44, 31, 21, 12,  7,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.50667 C=-0.25333
 | 
	
		
			
				|  |  | -+         0,  2,  6, 12, 20, 30, 43, 49, 64, 86, 98,108,116,122,125,127,127,125,122,116,108, 98, 86, 64, 49, 43, 30, 20, 12,  6,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.48000 C=-0.24000
 | 
	
		
			
				|  |  | -+         0,  2,  6, 12, 19, 29, 42, 47, 63, 85, 98,108,117,123,127,130,130,127,123,117,108, 98, 85, 63, 47, 42, 29, 19, 12,  6,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.45333 C=-0.22667
 | 
	
		
			
				|  |  | -+         0,  2,  6, 11, 19, 28, 41, 46, 62, 85, 97,108,118,125,129,132,132,129,125,118,108, 97, 85, 62, 46, 41, 28, 19, 11,  6,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.42667 C=-0.21333
 | 
	
		
			
				|  |  | -+         0,  2,  5, 11, 18, 28, 40, 45, 61, 84, 97,108,119,126,131,134,134,131,126,119,108, 97, 84, 61, 45, 40, 28, 18, 11,  5,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.40000 C=-0.20000
 | 
	
		
			
				|  |  | -+         0,  2,  5, 10, 18, 27, 39, 44, 60, 84, 96,109,119,127,134,136,136,134,127,119,109, 96, 84, 60, 44, 39, 27, 18, 10,  5,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.37333 C=-0.18667
 | 
	
		
			
				|  |  | -+         0,  1,  5, 10, 17, 26, 38, 43, 58, 82, 96,109,120,129,135,139,139,135,129,120,109, 96, 82, 58, 43, 38, 26, 17, 10,  5,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.34667 C=-0.17333
 | 
	
		
			
				|  |  | -+         0,  2,  4, 10, 16, 25, 37, 42, 57, 81, 96,109,121,131,137,141,141,137,131,121,109, 96, 81, 57, 42, 37, 25, 16, 10,  4,  2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.32000 C=-0.16000
 | 
	
		
			
				|  |  | -+         0,  1,  4,  9, 15, 24, 36, 41, 56, 81, 95,110,122,132,139,143,143,139,132,122,110, 95, 81, 56, 41, 36, 24, 15,  9,  4,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.29333 C=-0.14667
 | 
	
		
			
				|  |  | -+         0,  1,  4,  8, 15, 23, 35, 40, 55, 80, 95,110,123,133,141,146,146,141,133,123,110, 95, 80, 55, 40, 35, 23, 15,  8,  4,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.26667 C=-0.13333
 | 
	
		
			
				|  |  | -+         0,  1,  4,  8, 14, 22, 33, 38, 54, 79, 95,110,124,135,143,148,148,143,135,124,110, 95, 79, 54, 38, 33, 22, 14,  8,  4,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.24000 C=-0.12000
 | 
	
		
			
				|  |  | -+         0,  1,  4,  7, 14, 21, 33, 37, 53, 78, 94,110,125,136,145,150,150,145,136,125,110, 94, 78, 53, 37, 33, 21, 14,  7,  4,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.21333 C=-0.10667
 | 
	
		
			
				|  |  | -+         0,  1,  3,  7, 13, 20, 32, 36, 52, 77, 94,110,127,138,147,152,152,147,138,127,110, 94, 77, 52, 36, 32, 20, 13,  7,  3,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.18667 C=-0.09333
 | 
	
		
			
				|  |  | -+         0,  1,  3,  7, 12, 20, 30, 35, 51, 77, 93,111,125,140,149,155,155,149,140,125,111, 93, 77, 51, 35, 30, 20, 12,  7,  3,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.16000 C=-0.08000
 | 
	
		
			
				|  |  | -+         0,  1,  3,  6, 11, 19, 29, 34, 50, 76, 93,111,128,141,151,157,157,151,141,128,111, 93, 76, 50, 34, 29, 19, 11,  6,  3,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.13333 C=-0.06667
 | 
	
		
			
				|  |  | -+         0,  1,  3,  5, 11, 18, 28, 33, 49, 75, 93,111,129,143,153,159,159,153,143,129,111, 93, 75, 49, 33, 28, 18, 11,  5,  3,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.10667 C=-0.05333
 | 
	
		
			
				|  |  | -+         0,  1,  2,  5, 10, 17, 27, 32, 48, 74, 93,111,130,144,155,161,161,155,144,130,111, 93, 74, 48, 32, 27, 17, 10,  5,  2,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.08000 C=-0.04000
 | 
	
		
			
				|  |  | -+         0,  1,  2,  5,  9, 16, 26, 31, 46, 73, 92,112,130,145,157,164,164,157,145,130,112, 92, 73, 46, 31, 26, 16,  9,  5,  2,  1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.05333 C=-0.02667
 | 
	
		
			
				|  |  | -+         0,  0,  2,  4,  9, 15, 25, 29, 45, 72, 92,112,131,147,159,166,166,159,147,131,112, 92, 72, 45, 29, 25, 15,  9,  4,  2,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.02667 C=-0.01333
 | 
	
		
			
				|  |  | -+         0,  0,  1,  4,  8, 14, 24, 28, 44, 72, 92,112,132,148,161,168,168,161,148,132,112, 92, 72, 44, 28, 24, 14,  8,  4,  1,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=1.00000 C=0.00000
 | 
	
		
			
				|  |  | -+         0,  0,  1,  4,  7, 14, 23, 27, 43, 71, 91,112,133,150,163,170,170,163,150,133,112, 91, 71, 43, 27, 23, 14,  7,  4,  1,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.97333 C=0.01333
 | 
	
		
			
				|  |  | -+         0,  0,  1,  3,  7, 12, 22, 26, 42, 70, 91,113,133,152,165,173,173,165,152,133,113, 91, 70, 42, 26, 22, 12,  7,  3,  1,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.94667 C=0.02667
 | 
	
		
			
				|  |  | -+         0,  0,  1,  2,  6, 12, 21, 25, 41, 69, 90,113,135,153,167,175,175,167,153,135,113, 90, 69, 41, 25, 21, 12,  6,  2,  1,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.92000 C=0.04000
 | 
	
		
			
				|  |  | -+         0,  0,  0,  2,  5, 11, 20, 24, 40, 68, 90,113,136,154,169,177,177,169,154,136,113, 90, 68, 40, 24, 20, 11,  5,  2,  0,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.89333 C=0.05333
 | 
	
		
			
				|  |  | -+         0,  0,  0,  1,  5, 10, 19, 23, 39, 67, 90,114,136,156,171,179,179,171,156,136,114, 90, 67, 39, 23, 19, 10,  5,  1,  0,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.86667 C=0.06667
 | 
	
		
			
				|  |  | -+         0,  0,  0,  1,  4,  9, 18, 22, 38, 66, 89,114,137,157,173,182,182,173,157,137,114, 89, 66, 38, 22, 18,  9,  4,  1,  0,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.84000 C=0.08000
 | 
	
		
			
				|  |  | -+         0,  0, -1,  1,  3,  9, 17, 21, 37, 65, 89,114,138,159,175,184,184,175,159,138,114, 89, 65, 37, 21, 17,  9,  3,  1, -1,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.81333 C=0.09333
 | 
	
		
			
				|  |  | -+         0,  0, -1,  0,  3,  7, 16, 19, 36, 65, 89,114,139,160,177,186,186,177,160,139,114, 89, 65, 36, 19, 16,  7,  3,  0, -1,  0,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.78667 C=0.10667
 | 
	
		
			
				|  |  | -+         0, -1, -1,  0,  2,  6, 15, 18, 35, 64, 88,115,139,162,179,188,188,179,162,139,115, 88, 64, 35, 18, 15,  6,  2,  0, -1, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.76000 C=0.12000
 | 
	
		
			
				|  |  | -+         0, -1, -1, -1,  1,  6, 14, 17, 33, 63, 88,115,141,163,181,191,191,181,163,141,115, 88, 63, 33, 17, 14,  6,  1, -1, -1, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.73333 C=0.13333
 | 
	
		
			
				|  |  | -+         0, -1, -1, -1,  0,  5, 13, 16, 32, 62, 87,115,142,165,183,193,193,183,165,142,115, 87, 62, 32, 16, 13,  5,  0, -1, -1, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.70667 C=0.14667
 | 
	
		
			
				|  |  | -+         0, -1, -1, -2,  0,  4, 12, 15, 31, 61, 87,115,143,166,185,195,195,185,166,143,115, 87, 61, 31, 15, 12,  4,  0, -2, -1, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.68000 C=0.16000
 | 
	
		
			
				|  |  | -+         0, -1, -2, -2, -1,  3, 11, 14, 30, 61, 87,116,142,168,187,197,197,187,168,142,116, 87, 61, 30, 14, 11,  3, -1, -2, -2, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.65333 C=0.17333
 | 
	
		
			
				|  |  | -+         0, -1, -2, -3, -1,  2, 10, 13, 29, 60, 86,116,144,169,189,200,200,189,169,144,116, 86, 60, 29, 13, 10,  2, -1, -3, -2, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.62667 C=0.18667
 | 
	
		
			
				|  |  | -+         0, -1, -3, -3, -2,  1,  9, 12, 28, 59, 86,116,145,171,191,202,202,191,171,145,116, 86, 59, 28, 12,  9,  1, -2, -3, -3, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.60000 C=0.20000
 | 
	
		
			
				|  |  | -+         0, -1, -3, -3, -3,  0,  8, 10, 27, 58, 86,116,146,172,193,204,204,193,172,146,116, 86, 58, 27, 10,  8,  0, -3, -3, -3, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.57333 C=0.21333
 | 
	
		
			
				|  |  | -+         0, -1, -3, -4, -3, -1,  7,  9, 26, 57, 86,116,147,174,194,207,207,194,174,147,116, 86, 57, 26,  9,  7, -1, -3, -4, -3, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.54667 C=0.22667
 | 
	
		
			
				|  |  | -+         0, -2, -3, -5, -4, -1,  5,  8, 25, 57, 85,117,148,176,196,209,209,196,176,148,117, 85, 57, 25,  8,  5, -1, -4, -5, -3, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.52000 C=0.24000
 | 
	
		
			
				|  |  | -+         0, -1, -4, -5, -5, -2,  4,  7, 24, 55, 85,117,149,177,199,211,211,199,177,149,117, 85, 55, 24,  7,  4, -2, -5, -5, -4, -1,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.49333 C=0.25333
 | 
	
		
			
				|  |  | -+         0, -2, -4, -5, -6, -3,  3,  6, 23, 55, 84,117,150,178,200,214,214,200,178,150,117, 84, 55, 23,  6,  3, -3, -6, -5, -4, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.46667 C=0.26667
 | 
	
		
			
				|  |  | -+         0, -2, -4, -6, -6, -4,  2,  6, 22, 54, 84,118,150,180,202,216,216,202,180,150,118, 84, 54, 22,  6,  2, -4, -6, -6, -4, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.44000 C=0.28000
 | 
	
		
			
				|  |  | -+         0, -2, -4, -6, -7, -5,  2,  5, 21, 53, 83,118,150,181,205,218,218,205,181,150,118, 83, 53, 21,  5,  2, -5, -7, -6, -4, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.41333 C=0.29333
 | 
	
		
			
				|  |  | -+         0, -2, -4, -7, -7, -6,  0,  5, 20, 53, 83,118,152,183,207,220,220,207,183,152,118, 83, 53, 20,  5,  0, -6, -7, -7, -4, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.38667 C=0.30667
 | 
	
		
			
				|  |  | -+         0, -2, -5, -7, -8, -7, -1,  4, 19, 52, 83,118,153,185,208,223,223,208,185,153,118, 83, 52, 19,  4, -1, -7, -8, -7, -5, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.36000 C=0.32000
 | 
	
		
			
				|  |  | -+         0, -2, -5, -8, -8, -8, -2,  3, 19, 51, 83,118,155,186,210,225,225,210,186,155,118, 83, 51, 19,  3, -2, -8, -8, -8, -5, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.33333 C=0.33333
 | 
	
		
			
				|  |  | -+         0, -2, -6, -8,-10, -8, -3,  2, 18, 50, 82,119,155,187,213,227,227,213,187,155,119, 82, 50, 18,  2, -3, -8,-10, -8, -6, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.32667 C=0.33667
 | 
	
		
			
				|  |  | -+         0, -2, -6, -8,-10, -8, -3,  2, 18, 49, 82,119,155,188,213,228,228,213,188,155,119, 82, 49, 18,  2, -3, -8,-10, -8, -6, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.32000 C=0.34000
 | 
	
		
			
				|  |  | -+         0, -2, -6, -8,-10, -9, -3,  2, 18, 49, 82,119,155,188,214,228,228,214,188,155,119, 82, 49, 18,  2, -3, -9,-10, -8, -6, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.31333 C=0.34333
 | 
	
		
			
				|  |  | -+         0, -2, -6, -8,-10, -9, -4,  1, 18, 49, 82,119,155,188,214,229,229,214,188,155,119, 82, 49, 18,  1, -4, -9,-10, -8, -6, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.30667 C=0.34667
 | 
	
		
			
				|  |  | -+         0, -2, -6, -9,-10, -9, -4,  1, 18, 49, 82,119,156,189,214,229,229,214,189,156,119, 82, 49, 18,  1, -4, -9,-10, -9, -6, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.30000 C=0.35000
 | 
	
		
			
				|  |  | -+         0, -3, -5, -9,-10,-10, -4,  1, 18, 49, 82,119,156,189,215,230,230,215,189,156,119, 82, 49, 18,  1, -4,-10,-10, -9, -5, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.29333 C=0.35333
 | 
	
		
			
				|  |  | -+         0, -2, -6, -9,-10,-10, -4,  1, 17, 48, 82,119,156,190,215,231,231,215,190,156,119, 82, 48, 17,  1, -4,-10,-10, -9, -6, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.28667 C=0.35667
 | 
	
		
			
				|  |  | -+         0, -2, -6, -9,-11,-10, -5,  1, 17, 48, 82,119,157,190,216,231,231,216,190,157,119, 82, 48, 17,  1, -5,-10,-11, -9, -6, -2,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.28000 C=0.36000
 | 
	
		
			
				|  |  | -+         0, -3, -6, -9,-11,-10, -5,  0, 17, 48, 82,119,157,190,217,231,231,217,190,157,119, 82, 48, 17,  0, -5,-10,-11, -9, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.27333 C=0.36333
 | 
	
		
			
				|  |  | -+         0, -3, -6, -9,-11,-11, -5,  0, 17, 48, 82,119,157,191,217,232,232,217,191,157,119, 82, 48, 17,  0, -5,-11,-11, -9, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.26667 C=0.36667
 | 
	
		
			
				|  |  | -+         0, -3, -6, -9,-11,-11, -5,  0, 17, 48, 81,119,157,191,217,233,233,217,191,157,119, 81, 48, 17,  0, -5,-11,-11, -9, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.26000 C=0.37000
 | 
	
		
			
				|  |  | -+         0, -3, -6,-10,-11,-11, -5,  0, 16, 47, 81,120,156,191,218,233,233,218,191,156,120, 81, 47, 16,  0, -5,-11,-11,-10, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.25333 C=0.37333
 | 
	
		
			
				|  |  | -+         0, -3, -6, -9,-12,-11, -6,  0, 16, 47, 81,119,158,192,218,234,234,218,192,158,119, 81, 47, 16,  0, -6,-11,-12, -9, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.24667 C=0.37667
 | 
	
		
			
				|  |  | -+         0, -3, -6,-10,-12,-11, -6,  0, 16, 47, 81,120,157,192,219,234,234,219,192,157,120, 81, 47, 16,  0, -6,-11,-12,-10, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.24000 C=0.38000
 | 
	
		
			
				|  |  | -+         0, -3, -6,-10,-12,-12, -6, -1, 16, 47, 81,120,158,193,219,235,235,219,193,158,120, 81, 47, 16, -1, -6,-12,-12,-10, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.23333 C=0.38333
 | 
	
		
			
				|  |  | -+         0, -3, -6,-10,-12,-12, -6, -1, 16, 46, 81,120,158,193,220,236,236,220,193,158,120, 81, 46, 16, -1, -6,-12,-12,-10, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.22667 C=0.38667
 | 
	
		
			
				|  |  | -+         0, -3, -6,-10,-12,-12, -7, -1, 15, 47, 80,120,158,194,220,236,236,220,194,158,120, 80, 47, 15, -1, -7,-12,-12,-10, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.22000 C=0.39000
 | 
	
		
			
				|  |  | -+         0, -3, -6,-10,-13,-12, -7, -1, 15, 46, 80,120,159,194,221,237,237,221,194,159,120, 80, 46, 15, -1, -7,-12,-13,-10, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.21333 C=0.39333
 | 
	
		
			
				|  |  | -+         0, -3, -6,-10,-13,-12, -8, -1, 15, 46, 80,120,159,194,221,237,237,221,194,159,120, 80, 46, 15, -1, -8,-12,-13,-10, -6, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.20667 C=0.39667
 | 
	
		
			
				|  |  | -+         0, -3, -7,-10,-13,-12, -8, -2, 15, 46, 80,120,159,194,222,238,238,222,194,159,120, 80, 46, 15, -2, -8,-12,-13,-10, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.20000 C=0.40000
 | 
	
		
			
				|  |  | -+         0, -3, -7,-10,-13,-13, -8, -2, 15, 45, 81,120,159,195,222,238,238,222,195,159,120, 81, 45, 15, -2, -8,-13,-13,-10, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.19333 C=0.40333
 | 
	
		
			
				|  |  | -+         0, -3, -7,-11,-13,-13, -8, -2, 15, 45, 81,120,160,195,223,239,239,223,195,160,120, 81, 45, 15, -2, -8,-13,-13,-11, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.18667 C=0.40667
 | 
	
		
			
				|  |  | -+         0, -3, -7,-10,-14,-13, -9, -2, 14, 45, 80,120,160,196,223,240,240,223,196,160,120, 80, 45, 14, -2, -9,-13,-14,-10, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.18000 C=0.41000
 | 
	
		
			
				|  |  | -+         0, -3, -7,-11,-13,-13, -9, -2, 14, 45, 80,120,160,196,224,240,240,224,196,160,120, 80, 45, 14, -2, -9,-13,-13,-11, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.17333 C=0.41333
 | 
	
		
			
				|  |  | -+         0, -3, -7,-11,-13,-14, -9, -3, 14, 45, 80,120,160,196,225,240,240,225,196,160,120, 80, 45, 14, -3, -9,-14,-13,-11, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.16667 C=0.41667
 | 
	
		
			
				|  |  | -+         0, -3, -7,-11,-14,-14, -9, -3, 14, 44, 80,120,161,197,225,241,241,225,197,161,120, 80, 44, 14, -3, -9,-14,-14,-11, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.16000 C=0.42000
 | 
	
		
			
				|  |  | -+         0, -3, -7,-11,-14,-14,-10, -3, 14, 44, 80,120,161,197,225,242,242,225,197,161,120, 80, 44, 14, -3,-10,-14,-14,-11, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.15333 C=0.42333
 | 
	
		
			
				|  |  | -+         0, -3, -7,-11,-14,-14,-10, -3, 13, 44, 80,120,161,197,226,242,242,226,197,161,120, 80, 44, 13, -3,-10,-14,-14,-11, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.14667 C=0.42667
 | 
	
		
			
				|  |  | -+         0, -3, -7,-11,-15,-14,-10, -4, 14, 43, 80,120,163,198,226,243,243,226,198,163,120, 80, 43, 14, -4,-10,-14,-15,-11, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.14000 C=0.43000
 | 
	
		
			
				|  |  | -+         0, -3, -7,-12,-14,-15,-10, -4, 14, 43, 80,120,163,198,227,243,243,227,198,163,120, 80, 43, 14, -4,-10,-15,-14,-12, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.13333 C=0.43333
 | 
	
		
			
				|  |  | -+         0, -3, -7,-12,-14,-15,-11, -4, 13, 43, 79,121,161,199,227,244,244,227,199,161,121, 79, 43, 13, -4,-11,-15,-14,-12, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.12667 C=0.43667
 | 
	
		
			
				|  |  | -+         0, -3, -7,-12,-14,-15,-11, -4, 13, 43, 79,120,163,199,228,245,245,228,199,163,120, 79, 43, 13, -4,-11,-15,-14,-12, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.12000 C=0.44000
 | 
	
		
			
				|  |  | -+         0, -3, -7,-12,-15,-15,-12, -5, 13, 43, 79,121,162,199,228,245,245,228,199,162,121, 79, 43, 13, -5,-12,-15,-15,-12, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.11333 C=0.44333
 | 
	
		
			
				|  |  | -+         0, -3, -7,-12,-15,-16,-11, -5, 13, 42, 79,121,162,200,229,246,246,229,200,162,121, 79, 42, 13, -5,-11,-16,-15,-12, -7, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.10667 C=0.44667
 | 
	
		
			
				|  |  | -+         0, -3, -8,-12,-15,-16,-12, -5, 13, 42, 79,121,162,200,229,246,246,229,200,162,121, 79, 42, 13, -5,-12,-16,-15,-12, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.10000 C=0.45000
 | 
	
		
			
				|  |  | -+         0, -3, -8,-12,-16,-16,-12, -6, 13, 42, 79,121,163,200,230,247,247,230,200,163,121, 79, 42, 13, -6,-12,-16,-16,-12, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.09333 C=0.45333
 | 
	
		
			
				|  |  | -+         0, -3, -8,-12,-16,-16,-13, -5, 12, 42, 79,121,163,201,230,248,248,230,201,163,121, 79, 42, 12, -5,-13,-16,-16,-12, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.08667 C=0.45667
 | 
	
		
			
				|  |  | -+         0, -3, -8,-12,-16,-16,-13, -5, 12, 41, 79,121,163,201,231,248,248,231,201,163,121, 79, 41, 12, -5,-13,-16,-16,-12, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.08000 C=0.46000
 | 
	
		
			
				|  |  | -+         0, -3, -8,-12,-16,-17,-13, -6, 12, 41, 79,121,163,201,232,248,248,232,201,163,121, 79, 41, 12, -6,-13,-17,-16,-12, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.07333 C=0.46333
 | 
	
		
			
				|  |  | -+         0, -3, -8,-13,-16,-17,-13, -6, 12, 41, 79,121,164,202,232,249,249,232,202,164,121, 79, 41, 12, -6,-13,-17,-16,-13, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.06667 C=0.46667
 | 
	
		
			
				|  |  | -+         0, -3, -8,-13,-16,-17,-14, -6, 11, 41, 79,121,164,202,233,249,249,233,202,164,121, 79, 41, 11, -6,-14,-17,-16,-13, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.06000 C=0.47000
 | 
	
		
			
				|  |  | -+         0, -3, -8,-13,-16,-18,-14, -6, 11, 40, 79,121,164,203,233,250,250,233,203,164,121, 79, 40, 11, -6,-14,-18,-16,-13, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.05333 C=0.47333
 | 
	
		
			
				|  |  | -+         0, -3, -8,-13,-17,-18,-14, -6, 11, 40, 79,121,165,203,233,251,251,233,203,165,121, 79, 40, 11, -6,-14,-18,-17,-13, -8, -3,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.04667 C=0.47667
 | 
	
		
			
				|  |  | -+         0, -4, -8,-13,-17,-18,-14, -7, 11, 40, 79,121,166,203,234,251,251,234,203,166,121, 79, 40, 11, -7,-14,-18,-17,-13, -8, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.04000 C=0.48000
 | 
	
		
			
				|  |  | -+         0, -4, -8,-13,-17,-18,-14, -7, 11, 40, 78,121,166,204,234,251,251,234,204,166,121, 78, 40, 11, -7,-14,-18,-17,-13, -8, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.03333 C=0.48333
 | 
	
		
			
				|  |  | -+         0, -4, -8,-14,-17,-18,-15, -7, 11, 40, 78,122,164,204,235,252,252,235,204,164,122, 78, 40, 11, -7,-15,-18,-17,-14, -8, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.02667 C=0.48667
 | 
	
		
			
				|  |  | -+         0, -4, -8,-14,-17,-19,-15, -7, 10, 40, 78,122,164,205,235,253,253,235,205,164,122, 78, 40, 10, -7,-15,-19,-17,-14, -8, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.02000 C=0.49000
 | 
	
		
			
				|  |  | -+         0, -4, -8,-14,-17,-19,-15, -7, 10, 39, 78,122,164,205,236,253,253,236,205,164,122, 78, 39, 10, -7,-15,-19,-17,-14, -8, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.01333 C=0.49333
 | 
	
		
			
				|  |  | -+         0, -4, -8,-14,-18,-19,-16, -7,  9, 40, 78,122,165,205,236,254,254,236,205,165,122, 78, 40,  9, -7,-16,-19,-18,-14, -8, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.00667 C=0.49667
 | 
	
		
			
				|  |  | -+         0, -4, -9,-14,-18,-19,-15, -8, 10, 39, 78,122,166,206,236,254,254,236,206,166,122, 78, 39, 10, -8,-15,-19,-18,-14, -9, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+      { // B=0.00000 C=0.50000
 | 
	
		
			
				|  |  | -+         0, -4, -8,-14,-18,-19,-16, -8,  9, 39, 77,122,166,206,237,255,255,237,206,166,122, 77, 39,  9, -8,-16,-19,-18,-14, -8, -4,  0,
 | 
	
		
			
				|  |  | -+      },
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+  int index = (sharpness + 1.0f) * 50.0f + 0.5f;
 | 
	
		
			
				|  |  | -+  if (index >=0 && index <= 100)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    const int16_t *coef = mitchells[index];
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    char command[33*12];
 | 
	
		
			
				|  |  | -+    char response[33*12];
 | 
	
		
			
				|  |  | -+    unsigned int len = sprintf(command, "scaling_kernel ");
 | 
	
		
			
				|  |  | -+    for (int i=0; i < 32; i++) {
 | 
	
		
			
				|  |  | -+       if (len + 12 < sizeof command)
 | 
	
		
			
				|  |  | -+         len += sprintf(command+len, "%d ", coef[i]);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    // no interpolate flag
 | 
	
		
			
				|  |  | -+    if (len + 12 < sizeof command)
 | 
	
		
			
				|  |  | -+      len += sprintf(command+len, " %d", 0);
 | 
	
		
			
				|  |  | -+    //printf("%i: %s\n", index, command);
 | 
	
		
			
				|  |  | -+    vc_gencmd(response, sizeof response, command);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - void COMXPlayer::Process()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   bool bOmxWaitVideo = false;
 | 
	
		
			
				|  |  | -@@ -1183,6 +1511,8 @@ void COMXPlayer::Process()
 | 
	
		
			
				|  |  | -     SetCaching(CACHESTATE_FLUSH);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   EDEINTERLACEMODE current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
 | 
	
		
			
				|  |  | -+  float current_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
 | 
	
		
			
				|  |  | -+  SetSharpness(current_sharpness);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   while (!m_bAbortRequest)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -1214,6 +1544,13 @@ void COMXPlayer::Process()
 | 
	
		
			
				|  |  | -         current_deinterlace = CMediaSettings::Get().GetCurrentVideoSettings().m_DeinterlaceMode;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+      // if sharpness setting has changed, we should update it
 | 
	
		
			
				|  |  | -+      if (current_sharpness != CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        current_sharpness = CMediaSettings::Get().GetCurrentVideoSettings().m_Sharpness;
 | 
	
		
			
				|  |  | -+        SetSharpness(current_sharpness);
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -       m_video_fifo = (int)(100.0*(m_omxPlayerVideo.GetDecoderBufferSize()-m_omxPlayerVideo.GetDecoderFreeSpace())/m_omxPlayerVideo.GetDecoderBufferSize());
 | 
	
		
			
				|  |  | -       m_audio_fifo = (int)(100.0*audio_fifo/m_omxPlayerAudio.GetCacheTotal());
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -4577,6 +4914,7 @@ void COMXPlayer::GetRenderFeatures(std::vector<int> &renderFeatures)
 | 
	
		
			
				|  |  | -   renderFeatures.push_back(RENDERFEATURE_CROP);
 | 
	
		
			
				|  |  | -   renderFeatures.push_back(RENDERFEATURE_PIXEL_RATIO);
 | 
	
		
			
				|  |  | -   renderFeatures.push_back(RENDERFEATURE_ZOOM);
 | 
	
		
			
				|  |  | -+  renderFeatures.push_back(RENDERFEATURE_SHARPNESS);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COMXPlayer::GetDeinterlaceMethods(std::vector<int> &deinterlaceMethods)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 97a3f2347e45eee8f960a2190891d4bd9de3dda0 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 10 Apr 2014 17:24:51 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 68/94] [rpi] Include ntsc frequencies in list of supported
 | 
	
		
			
				|  |  | - resolutions
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp         |  8 ------
 | 
	
		
			
				|  |  | - xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 35 ++++++++++++++++++++++++-
 | 
	
		
			
				|  |  | - xbmc/windowing/egl/WinSystemEGL.cpp             |  3 ++-
 | 
	
		
			
				|  |  | - 3 files changed, 36 insertions(+), 10 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index 019f4b2..b8a3871 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -556,14 +556,6 @@ bool OMXPlayerVideo::OpenDecoder()
 | 
	
		
			
				|  |  | -         m_omxVideo.GetDecoderName().c_str() , m_hints.width, m_hints.height, m_hints.profile, m_fFrameRate);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     m_codecname = m_omxVideo.GetDecoderName();
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    // if we are closer to ntsc version of framerate, let gpu know
 | 
	
		
			
				|  |  | --    int   iFrameRate  = (int)(m_fFrameRate + 0.5f);
 | 
	
		
			
				|  |  | --    bool  bNtscFreq  = fabs(m_fFrameRate * 1001.0f / 1000.0f - iFrameRate) < fabs(m_fFrameRate - iFrameRate);
 | 
	
		
			
				|  |  | --    char  response[80], command[80];
 | 
	
		
			
				|  |  | --    sprintf(command, "hdmi_ntsc_freqs %d", bNtscFreq);
 | 
	
		
			
				|  |  | --    CLog::Log(LOGINFO, "OMXPlayerVideo::OpenDecoder fps: %f %s\n", m_fFrameRate, command);
 | 
	
		
			
				|  |  | --    m_DllBcmHost.vc_gencmd(response, sizeof response, command);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // start from assuming all recent frames had valid pts
 | 
	
		
			
				|  |  | -diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -index dc47095..21b8cc4 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -@@ -20,6 +20,7 @@
 | 
	
		
			
				|  |  | - #include "system.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include <EGL/egl.h>
 | 
	
		
			
				|  |  | -+#include <math.h>
 | 
	
		
			
				|  |  | - #include "EGLNativeTypeRaspberryPI.h"
 | 
	
		
			
				|  |  | - #include "utils/log.h"
 | 
	
		
			
				|  |  | - #include "guilib/gui3d.h"
 | 
	
		
			
				|  |  | -@@ -236,6 +237,18 @@ bool CEGLNativeTypeRaspberryPI::SetNativeResolution(const RESOLUTION_INFO &res)
 | 
	
		
			
				|  |  | -       property.param2 = 0;
 | 
	
		
			
				|  |  | -       vc_tv_hdmi_set_property(&property);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    HDMI_PROPERTY_PARAM_T property;
 | 
	
		
			
				|  |  | -+    property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
 | 
	
		
			
				|  |  | -+    // if we are closer to ntsc version of framerate, let gpu know
 | 
	
		
			
				|  |  | -+    int   iFrameRate  = (int)(res.fRefreshRate + 0.5f);
 | 
	
		
			
				|  |  | -+    if (fabsf(res.fRefreshRate * (1001.0f / 1000.0f) - iFrameRate) < fabsf(res.fRefreshRate - iFrameRate))
 | 
	
		
			
				|  |  | -+      property.param1 = HDMI_PIXEL_CLOCK_TYPE_NTSC;
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+      property.param1 = HDMI_PIXEL_CLOCK_TYPE_PAL;
 | 
	
		
			
				|  |  | -+    property.param2 = 0;
 | 
	
		
			
				|  |  | -+    vc_tv_hdmi_set_property(&property);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     int success = m_DllBcmHost->vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_HDMI, GETFLAGS_GROUP(res.dwFlags), GETFLAGS_MODE(res.dwFlags));
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     if (success == 0)
 | 
	
		
			
				|  |  | -@@ -442,7 +455,10 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
 | 
	
		
			
				|  |  | -         m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
 | 
	
		
			
				|  |  | -         m_desktopRes.fPixelRatio *= 0.5;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --      m_desktopRes.fRefreshRate = (float)tv_state.display.hdmi.frame_rate;
 | 
	
		
			
				|  |  | -+      HDMI_PROPERTY_PARAM_T property;
 | 
	
		
			
				|  |  | -+      property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
 | 
	
		
			
				|  |  | -+      vc_tv_hdmi_get_property(&property);
 | 
	
		
			
				|  |  | -+      m_desktopRes.fRefreshRate = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? tv_state.display.hdmi.frame_rate * (1000.0f/1001.0f) : tv_state.display.hdmi.frame_rate;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     else // sdtv
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -@@ -576,6 +592,12 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -       res.iSubtitles    = (int)(0.965 * res.iHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       AddUniqueResolution(res, resolutions);
 | 
	
		
			
				|  |  | -+      if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -+        res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
 | 
	
		
			
				|  |  | -+        AddUniqueResolution(res2, resolutions);
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       // Also add 3D versions of modes
 | 
	
		
			
				|  |  | -       if (tv->struct_3d_mask & HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL)
 | 
	
		
			
				|  |  | -@@ -590,6 +612,11 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         AddUniqueResolution(res2, resolutions);
 | 
	
		
			
				|  |  | -+        if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
 | 
	
		
			
				|  |  | -+          AddUniqueResolution(res2, resolutions);
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -       if (tv->struct_3d_mask & HDMI_3D_STRUCT_TOP_AND_BOTTOM)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -@@ -603,6 +630,12 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         AddUniqueResolution(res2, resolutions);
 | 
	
		
			
				|  |  | -+        if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
 | 
	
		
			
				|  |  | -+          AddUniqueResolution(res2, resolutions);
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/windowing/egl/WinSystemEGL.cpp b/xbmc/windowing/egl/WinSystemEGL.cpp
 | 
	
		
			
				|  |  | -index 0c32947..258a293 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/windowing/egl/WinSystemEGL.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/windowing/egl/WinSystemEGL.cpp
 | 
	
		
			
				|  |  | -@@ -34,6 +34,7 @@
 | 
	
		
			
				|  |  | - #include "EGLWrapper.h"
 | 
	
		
			
				|  |  | - #include "EGLQuirks.h"
 | 
	
		
			
				|  |  | - #include <vector>
 | 
	
		
			
				|  |  | -+#include <float.h>
 | 
	
		
			
				|  |  | - ////////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | - CWinSystemEGL::CWinSystemEGL() : CWinSystemBase()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -@@ -399,7 +400,7 @@ void CWinSystemEGL::UpdateResolutions()
 | 
	
		
			
				|  |  | -        resDesktop.iScreenWidth == resolutions[i].iScreenWidth &&
 | 
	
		
			
				|  |  | -        resDesktop.iScreenHeight == resolutions[i].iScreenHeight &&
 | 
	
		
			
				|  |  | -        (resDesktop.dwFlags & D3DPRESENTFLAG_MODEMASK) == (resolutions[i].dwFlags & D3DPRESENTFLAG_MODEMASK) &&
 | 
	
		
			
				|  |  | --       resDesktop.fRefreshRate == resolutions[i].fRefreshRate)
 | 
	
		
			
				|  |  | -+       fabs(resDesktop.fRefreshRate - resolutions[i].fRefreshRate) < FLT_EPSILON)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -       ResDesktop = res_index;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 6e000e35a42863a9db644692246c43300e4ab948 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 10 Apr 2014 17:26:20 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 69/94] [omxplayer] Allow a framerate callback from GPU to
 | 
	
		
			
				|  |  | - trigger a hdmi mode change
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp |  8 +++++---
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.h   |  4 ++--
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXVideo.cpp       | 35 +++++++++++++++++----------------
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXVideo.h         |  2 +-
 | 
	
		
			
				|  |  | - 4 files changed, 26 insertions(+), 23 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index b8a3871..e9010b1 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -694,7 +694,7 @@ void OMXPlayerVideo::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect,
 | 
	
		
			
				|  |  | -   player->SetVideoRect(SrcRect, DestRect);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, float display_aspect)
 | 
	
		
			
				|  |  | -+void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, float framerate, float display_aspect)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   RESOLUTION res  = g_graphicsContext.GetVideoResolution();
 | 
	
		
			
				|  |  | -   uint32_t video_width   = CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth;
 | 
	
		
			
				|  |  | -@@ -743,6 +743,8 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
 | 
	
		
			
				|  |  | -   else if( display_aspect != 0.0f )
 | 
	
		
			
				|  |  | -     iDisplayWidth = (int) (iDisplayHeight * display_aspect);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_fFrameRate = DVD_TIME_BASE / CDVDCodecUtils::NormalizeFrameduration((double)DVD_TIME_BASE / framerate);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   CLog::Log(LOGDEBUG,"%s - change configuration. video:%dx%d. framerate: %4.2f. %dx%d format: BYPASS",
 | 
	
		
			
				|  |  | -       __FUNCTION__, video_width, video_height, m_fFrameRate, iDisplayWidth, iDisplayHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -757,9 +759,9 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
 | 
	
		
			
				|  |  | -   g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void OMXPlayerVideo::ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float display_aspect)
 | 
	
		
			
				|  |  | -+void OMXPlayerVideo::ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float framerate, float display_aspect)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   OMXPlayerVideo *player = static_cast<OMXPlayerVideo*>(ctx);
 | 
	
		
			
				|  |  | --  player->ResolutionUpdateCallBack(width, height, display_aspect);
 | 
	
		
			
				|  |  | -+  player->ResolutionUpdateCallBack(width, height, framerate, display_aspect);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -index b49748f..33564dd 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -@@ -125,7 +125,7 @@ class OMXPlayerVideo : public CThread
 | 
	
		
			
				|  |  | -   int GetFreeSpace();
 | 
	
		
			
				|  |  | -   void  SetVideoRect(const CRect &SrcRect, const CRect &DestRect);
 | 
	
		
			
				|  |  | -   static void RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect);
 | 
	
		
			
				|  |  | --  void ResolutionUpdateCallBack(uint32_t width, uint32_t height, float pixel_aspect);
 | 
	
		
			
				|  |  | --  static void ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float pixel_aspect);
 | 
	
		
			
				|  |  | -+  void ResolutionUpdateCallBack(uint32_t width, uint32_t height, float framerate, float pixel_aspect);
 | 
	
		
			
				|  |  | -+  static void ResolutionUpdateCallBack(void *ctx, uint32_t width, uint32_t height, float framerate, float pixel_aspect);
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -index 66a351d..10a7530 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -@@ -171,6 +171,22 @@ bool COMXVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "%s::%s - error m_omx_decoder.GetParameter(OMX_IndexParamBrcmPixelAspectRatio) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  OMX_CONFIG_INTERLACETYPE interlace;
 | 
	
		
			
				|  |  | -+  OMX_INIT_STRUCTURE(interlace);
 | 
	
		
			
				|  |  | -+  interlace.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if(m_deinterlace_request == VS_DEINTERLACEMODE_FORCE)
 | 
	
		
			
				|  |  | -+    m_deinterlace = true;
 | 
	
		
			
				|  |  | -+  else if(m_deinterlace_request == VS_DEINTERLACEMODE_OFF)
 | 
	
		
			
				|  |  | -+    m_deinterlace = false;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -+      port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
 | 
	
		
			
				|  |  | -+      port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // let OMXPlayerVideo know about resolution so it can inform RenderManager
 | 
	
		
			
				|  |  | -   if (m_res_callback)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -178,7 +194,8 @@ bool COMXVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | -     if (pixel_aspect.nX && pixel_aspect.nY)
 | 
	
		
			
				|  |  | -       display_aspect = (float)pixel_aspect.nX * port_image.format.video.nFrameWidth /
 | 
	
		
			
				|  |  | -         ((float)pixel_aspect.nY * port_image.format.video.nFrameHeight);
 | 
	
		
			
				|  |  | --    m_res_callback(m_res_ctx, port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight, display_aspect);
 | 
	
		
			
				|  |  | -+    m_res_callback(m_res_ctx, port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
 | 
	
		
			
				|  |  | -+        port_image.format.video.xFramerate / (float)(1<<16), display_aspect);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (m_settings_changed)
 | 
	
		
			
				|  |  | -@@ -187,27 +204,11 @@ bool COMXVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | -     return true;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  OMX_CONFIG_INTERLACETYPE interlace;
 | 
	
		
			
				|  |  | --  OMX_INIT_STRUCTURE(interlace);
 | 
	
		
			
				|  |  | --  interlace.nPortIndex = m_omx_decoder.GetOutputPort();
 | 
	
		
			
				|  |  | --  omx_err = m_omx_decoder.GetConfig(OMX_IndexConfigCommonInterlace, &interlace);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if(m_deinterlace_request == VS_DEINTERLACEMODE_FORCE)
 | 
	
		
			
				|  |  | --    m_deinterlace = true;
 | 
	
		
			
				|  |  | --  else if(m_deinterlace_request == VS_DEINTERLACEMODE_OFF)
 | 
	
		
			
				|  |  | --    m_deinterlace = false;
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   if(!m_omx_render.Initialize("OMX.broadcom.video_render", OMX_IndexParamVideoInit))
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_omx_render.ResetEos();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | --      port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
 | 
	
		
			
				|  |  | --      port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   if(!m_omx_sched.Initialize("OMX.broadcom.video_scheduler", OMX_IndexParamVideoInit))
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h
 | 
	
		
			
				|  |  | -index d69f854..fd23e70 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXVideo.h
 | 
	
		
			
				|  |  | -@@ -38,7 +38,7 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define CLASSNAME "COMXVideo"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --typedef void (*ResolutionUpdateCallBackFn)(void *ctx, uint32_t width, uint32_t height, float display_aspect);
 | 
	
		
			
				|  |  | -+typedef void (*ResolutionUpdateCallBackFn)(void *ctx, uint32_t width, uint32_t height, float framerate, float display_aspect);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - class COMXVideo
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7d8653f297a2aeea7b10bf36732892878ae89334 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Fri, 11 Apr 2014 19:01:26 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 70/94] [omxplayer] Request to be notified about framerate
 | 
	
		
			
				|  |  | - changes
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXVideo.cpp | 14 ++++++++++++--
 | 
	
		
			
				|  |  | - 1 file changed, 12 insertions(+), 2 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -index 10a7530..148b16f 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -@@ -183,7 +183,7 @@ bool COMXVideo::PortSettingsChanged()
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -     m_deinterlace = interlace.eMode != OMX_InterlaceProgressive;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %dx%d@%.2f interlace:%d deinterlace:%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -       port_image.format.video.nFrameWidth, port_image.format.video.nFrameHeight,
 | 
	
		
			
				|  |  | -       port_image.format.video.xFramerate / (float)(1<<16), interlace.eMode, m_deinterlace);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -558,7 +558,17 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, EDEINTERLACEMODE de
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexConfigRequestCallback error (0%08x)\n", omx_err);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+  // request portsettingschanged on refresh rate change
 | 
	
		
			
				|  |  | -+  if (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") == ADJUST_REFRESHRATE_ALWAYS)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    notifications.nIndex = OMX_IndexParamPortDefinition;
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_decoder.SetParameter((OMX_INDEXTYPE)OMX_IndexConfigRequestCallback, ¬ifications);
 | 
	
		
			
				|  |  | -+    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "COMXVideo::Open OMX_IndexConfigRequestCallback error (0%08x)\n", omx_err);
 | 
	
		
			
				|  |  | -+      //return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE concanParam;
 | 
	
		
			
				|  |  | -   OMX_INIT_STRUCTURE(concanParam);
 | 
	
		
			
				|  |  | -   if(g_advancedSettings.m_omxDecodeStartWithValidFrame)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 12a54cc9ca0c0500f1d86173df0c8466270bd766 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 14 Apr 2014 17:04:57 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 71/94] [omxplayer] Support stereo view modes with scaling
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The Pi only supported a single view rectangle, which is sufficient for all mono view modes,
 | 
	
		
			
				|  |  | -but only supports a subset of stereo modes.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -To work around this, the scaling rectangles were ignored in 3D modes and 3D video was treated as unscaled.
 | 
	
		
			
				|  |  | -While this worked or square pixel, 16:9 content on a 16:9 display, it went wrong is various other conditions.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -@sraue reported that mono view of SBS/TAB content wasn't scaled correctly, and other forum reports
 | 
	
		
			
				|  |  | -aspect ratio errors in widescreen 3D videos.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -As it wasn't trivial to work around these bug reports, I've added a new stereo flags to the firmware
 | 
	
		
			
				|  |  | -that allows a second display region to be created for the second eye, allowing scaling to work.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -I've been through the video stereo modes (none, sbs, tab) and the display stereo modes (mono, sbs, tab)
 | 
	
		
			
				|  |  | -and all the zoom modes, and compared the scaling to xbmc on windows and all seem to match
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Requires udpated firmware.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 103 +++++++++++++++++++++-----------
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.h   |   4 +-
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXVideo.cpp       |  45 ++++++++------
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXVideo.h         |   3 +-
 | 
	
		
			
				|  |  | - 4 files changed, 100 insertions(+), 55 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index e9010b1..d5f3bec 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -97,6 +97,9 @@ OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock,
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_src_rect.SetRect(0, 0, 0, 0);
 | 
	
		
			
				|  |  | -   m_dst_rect.SetRect(0, 0, 0, 0);
 | 
	
		
			
				|  |  | -+  m_video_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+  m_display_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+  m_StereoInvert = false;
 | 
	
		
			
				|  |  | -   m_started = false;
 | 
	
		
			
				|  |  | -   m_iCurrentPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -   m_nextOverlay = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -@@ -120,6 +123,9 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints)
 | 
	
		
			
				|  |  | -   // force SetVideoRect to be called initially
 | 
	
		
			
				|  |  | -   m_src_rect.SetRect(0, 0, 0, 0);
 | 
	
		
			
				|  |  | -   m_dst_rect.SetRect(0, 0, 0, 0);
 | 
	
		
			
				|  |  | -+  m_video_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+  m_display_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+  m_StereoInvert = false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (!m_DllBcmHost.Load())
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -@@ -634,58 +640,85 @@ int OMXPlayerVideo::GetFreeSpace()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRect)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  CRect SrcRect = InSrcRect, DestRect = InDestRect;
 | 
	
		
			
				|  |  | -+  // we get called twice a frame for left/right. Can ignore the rights.
 | 
	
		
			
				|  |  | -+  if (g_graphicsContext.GetStereoView() == RENDER_STEREO_VIEW_RIGHT)
 | 
	
		
			
				|  |  | -+    return;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // in 3d modes skip this - we get called as the gui switches from left eye to right eye
 | 
	
		
			
				|  |  | -+  CRect SrcRect = InSrcRect, DestRect = InDestRect;
 | 
	
		
			
				|  |  | -   unsigned flags = GetStereoModeFlags(GetStereoMode());
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (CONF_FLAGS_STEREO_MODE_MASK(flags))
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if (g_graphicsContext.GetStereoMode() == RENDER_STEREO_MODE_MONO)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --       if (GetStereoMode() == "left_right")
 | 
	
		
			
				|  |  | --         SrcRect.SetRect(0, 0, m_hints.width>>1, m_hints.height);
 | 
	
		
			
				|  |  | --       else if (GetStereoMode() == "right_left")
 | 
	
		
			
				|  |  | --         SrcRect.SetRect(m_hints.width>>1, 0, m_hints.width, m_hints.height);
 | 
	
		
			
				|  |  | --       else if (GetStereoMode() == "top_bottom")
 | 
	
		
			
				|  |  | --         SrcRect.SetRect(0, 0, m_hints.width, m_hints.height>>1);
 | 
	
		
			
				|  |  | --       else if (GetStereoMode() == "bottom_top")
 | 
	
		
			
				|  |  | --         SrcRect.SetRect(0, m_hints.height>>1, m_hints.width, m_hints.height);
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --      SrcRect.SetRect(0, 0, m_hints.width, m_hints.height);
 | 
	
		
			
				|  |  | --    // interpreted as fullscreen
 | 
	
		
			
				|  |  | --    DestRect.SetRect(0, 0, 0, 0);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+  RENDER_STEREO_MODE video_stereo_mode = (flags & CONF_FLAGS_STEREO_MODE_SBS) ? RENDER_STEREO_MODE_SPLIT_VERTICAL :
 | 
	
		
			
				|  |  | -+                                         (flags & CONF_FLAGS_STEREO_MODE_TAB) ? RENDER_STEREO_MODE_SPLIT_HORIZONTAL : RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+  bool stereo_invert                   = (flags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false;
 | 
	
		
			
				|  |  | -+  RENDER_STEREO_MODE display_stereo_mode = g_graphicsContext.GetStereoMode();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // check if destination rect or video view mode has changed
 | 
	
		
			
				|  |  | --  if (m_dst_rect != DestRect || m_src_rect != SrcRect)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_src_rect  = SrcRect;
 | 
	
		
			
				|  |  | --    m_dst_rect  = DestRect;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | -+  if (!(m_dst_rect != DestRect) && !(m_src_rect != SrcRect) && m_video_stereo_mode == video_stereo_mode && m_display_stereo_mode == display_stereo_mode && m_StereoInvert == stereo_invert)
 | 
	
		
			
				|  |  | -     return;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "OMXPlayerVideo::%s %d,%d,%d,%d -> %d,%d,%d,%d (%d,%d,%d,%d,%s)", __func__,
 | 
	
		
			
				|  |  | -+      (int)SrcRect.x1, (int)SrcRect.y1, (int)SrcRect.x2, (int)SrcRect.y2,
 | 
	
		
			
				|  |  | -+      (int)DestRect.x1, (int)DestRect.y1, (int)DestRect.x2, (int)DestRect.y2,
 | 
	
		
			
				|  |  | -+      video_stereo_mode, display_stereo_mode, CMediaSettings::Get().GetCurrentVideoSettings().m_StereoInvert, g_graphicsContext.GetStereoView(), OMXPlayerVideo::GetStereoMode().c_str());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_src_rect = SrcRect;
 | 
	
		
			
				|  |  | -+  m_dst_rect = DestRect;
 | 
	
		
			
				|  |  | -+  m_video_stereo_mode = video_stereo_mode;
 | 
	
		
			
				|  |  | -+  m_display_stereo_mode = display_stereo_mode;
 | 
	
		
			
				|  |  | -+  m_StereoInvert = stereo_invert;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // might need to scale up m_dst_rect to display size as video decodes
 | 
	
		
			
				|  |  | -   // to separate video plane that is at display size.
 | 
	
		
			
				|  |  | -   RESOLUTION res = g_graphicsContext.GetVideoResolution();
 | 
	
		
			
				|  |  | -   CRect gui(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iWidth, CDisplaySettings::Get().GetResolutionInfo(res).iHeight);
 | 
	
		
			
				|  |  | -   CRect display(0, 0, CDisplaySettings::Get().GetResolutionInfo(res).iScreenWidth, CDisplaySettings::Get().GetResolutionInfo(res).iScreenHeight);
 | 
	
		
			
				|  |  | --  CRect dst_rect(m_dst_rect);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  switch (video_stereo_mode)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+  case RENDER_STEREO_MODE_SPLIT_VERTICAL:
 | 
	
		
			
				|  |  | -+    // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
 | 
	
		
			
				|  |  | -+    if (video_stereo_mode == display_stereo_mode && DestRect.x1 == 0.0f && DestRect.x2 * 2.0f == gui.Width() && !stereo_invert)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      SrcRect.x2 *= 2.0f;
 | 
	
		
			
				|  |  | -+      DestRect.x2 *= 2.0f;
 | 
	
		
			
				|  |  | -+      video_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+      display_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if (stereo_invert)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      SrcRect.x1 += m_hints.width / 2;
 | 
	
		
			
				|  |  | -+      SrcRect.x2 += m_hints.width / 2;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    break;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  case RENDER_STEREO_MODE_SPLIT_HORIZONTAL:
 | 
	
		
			
				|  |  | -+    // optimisation - use simpler display mode in common case of unscaled 3d with same display mode
 | 
	
		
			
				|  |  | -+    if (video_stereo_mode == display_stereo_mode && DestRect.y1 == 0.0f && DestRect.y2 * 2.0f == gui.Height() && !stereo_invert)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      SrcRect.y2 *= 2.0f;
 | 
	
		
			
				|  |  | -+      DestRect.y2 *= 2.0f;
 | 
	
		
			
				|  |  | -+      video_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+      display_stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if (stereo_invert)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      SrcRect.y1 += m_hints.height / 2;
 | 
	
		
			
				|  |  | -+      SrcRect.y2 += m_hints.height / 2;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    break;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  default: break;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if (gui != display)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     float xscale = display.Width()  / gui.Width();
 | 
	
		
			
				|  |  | -     float yscale = display.Height() / gui.Height();
 | 
	
		
			
				|  |  | --    dst_rect.x1 *= xscale;
 | 
	
		
			
				|  |  | --    dst_rect.x2 *= xscale;
 | 
	
		
			
				|  |  | --    dst_rect.y1 *= yscale;
 | 
	
		
			
				|  |  | --    dst_rect.y2 *= yscale;
 | 
	
		
			
				|  |  | -+    DestRect.x1 *= xscale;
 | 
	
		
			
				|  |  | -+    DestRect.x2 *= xscale;
 | 
	
		
			
				|  |  | -+    DestRect.y1 *= yscale;
 | 
	
		
			
				|  |  | -+    DestRect.y2 *= yscale;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  m_omxVideo.SetVideoRect(SrcRect, dst_rect);
 | 
	
		
			
				|  |  | -+  m_omxVideo.SetVideoRect(SrcRect, DestRect, video_stereo_mode, display_stereo_mode);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void OMXPlayerVideo::RenderUpdateCallBack(const void *ctx, const CRect &SrcRect, const CRect &DestRect)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -index 33564dd..6f19395 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -@@ -69,7 +69,9 @@ class OMXPlayerVideo : public CThread
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   CRect                     m_src_rect;
 | 
	
		
			
				|  |  | -   CRect                     m_dst_rect;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+  RENDER_STEREO_MODE        m_video_stereo_mode;
 | 
	
		
			
				|  |  | -+  RENDER_STEREO_MODE        m_display_stereo_mode;
 | 
	
		
			
				|  |  | -+  bool                      m_StereoInvert;
 | 
	
		
			
				|  |  | -   uint32_t                  m_history_valid_pts;
 | 
	
		
			
				|  |  | -   DllBcmHost                m_DllBcmHost;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXVideo.cpp b/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -index 148b16f..dceb8bf 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXVideo.cpp
 | 
	
		
			
				|  |  | -@@ -836,7 +836,7 @@ void COMXVideo::Reset(void)
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - ///////////////////////////////////////////////////////////////////////////////////////////
 | 
	
		
			
				|  |  | --void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect)
 | 
	
		
			
				|  |  | -+void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   CSingleLock lock (m_critSection);
 | 
	
		
			
				|  |  | -   if(!m_is_open)
 | 
	
		
			
				|  |  | -@@ -846,27 +846,36 @@ void COMXVideo::SetVideoRect(const CRect& SrcRect, const CRect& DestRect)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   OMX_INIT_STRUCTURE(configDisplay);
 | 
	
		
			
				|  |  | -   configDisplay.nPortIndex = m_omx_render.GetInputPort();
 | 
	
		
			
				|  |  | --  configDisplay.set                 = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT);
 | 
	
		
			
				|  |  | --  configDisplay.dest_rect.x_offset  = (int)(DestRect.x1+0.5f);
 | 
	
		
			
				|  |  | --  configDisplay.dest_rect.y_offset  = (int)(DestRect.y1+0.5f);
 | 
	
		
			
				|  |  | --  configDisplay.dest_rect.width     = (int)(DestRect.Width()+0.5f);
 | 
	
		
			
				|  |  | --  configDisplay.dest_rect.height    = (int)(DestRect.Height()+0.5f);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  configDisplay.src_rect.x_offset   = (int)(SrcRect.x1+0.5f);
 | 
	
		
			
				|  |  | --  configDisplay.src_rect.y_offset   = (int)(SrcRect.y1+0.5f);
 | 
	
		
			
				|  |  | --  configDisplay.src_rect.width      = (int)(SrcRect.Width()+0.5f);
 | 
	
		
			
				|  |  | --  configDisplay.src_rect.height     = (int)(SrcRect.Height()+0.5f);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (configDisplay.dest_rect.width == 0 || configDisplay.dest_rect.height == 0)
 | 
	
		
			
				|  |  | --    configDisplay.fullscreen = OMX_TRUE;
 | 
	
		
			
				|  |  | -+  configDisplay.set                 = (OMX_DISPLAYSETTYPE)(OMX_DISPLAY_SET_DEST_RECT|OMX_DISPLAY_SET_SRC_RECT|OMX_DISPLAY_SET_FULLSCREEN|OMX_DISPLAY_SET_NOASPECT|OMX_DISPLAY_SET_MODE);
 | 
	
		
			
				|  |  | -+  configDisplay.dest_rect.x_offset  = lrintf(DestRect.x1);
 | 
	
		
			
				|  |  | -+  configDisplay.dest_rect.y_offset  = lrintf(DestRect.y1);
 | 
	
		
			
				|  |  | -+  configDisplay.dest_rect.width     = lrintf(DestRect.Width());
 | 
	
		
			
				|  |  | -+  configDisplay.dest_rect.height    = lrintf(DestRect.Height());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  configDisplay.src_rect.x_offset   = lrintf(SrcRect.x1);
 | 
	
		
			
				|  |  | -+  configDisplay.src_rect.y_offset   = lrintf(SrcRect.y1);
 | 
	
		
			
				|  |  | -+  configDisplay.src_rect.width      = lrintf(SrcRect.Width());
 | 
	
		
			
				|  |  | -+  configDisplay.src_rect.height     = lrintf(SrcRect.Height());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  configDisplay.fullscreen = OMX_FALSE;
 | 
	
		
			
				|  |  | -+  configDisplay.noaspect = OMX_TRUE;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (video_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
 | 
	
		
			
				|  |  | -+    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_TOP_TO_TOP;
 | 
	
		
			
				|  |  | -+  else if (video_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && display_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
 | 
	
		
			
				|  |  | -+    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_TOP_TO_LEFT;
 | 
	
		
			
				|  |  | -+  else if (video_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
 | 
	
		
			
				|  |  | -+    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_LEFT_TO_TOP;
 | 
	
		
			
				|  |  | -+  else if (video_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && display_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
 | 
	
		
			
				|  |  | -+    configDisplay.mode = OMX_DISPLAY_MODE_STEREO_LEFT_TO_LEFT;
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | --    configDisplay.noaspect = OMX_TRUE;
 | 
	
		
			
				|  |  | -+    configDisplay.mode = OMX_DISPLAY_MODE_LETTERBOX;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "dest_rect.x_offset %d dest_rect.y_offset %d dest_rect.width %d dest_rect.height %d\n",
 | 
	
		
			
				|  |  | --      configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset, 
 | 
	
		
			
				|  |  | --      configDisplay.dest_rect.width, configDisplay.dest_rect.height);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s %d,%d,%d,%d -> %d,%d,%d,%d mode:%d", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -+      configDisplay.src_rect.x_offset, configDisplay.src_rect.y_offset, configDisplay.src_rect.width, configDisplay.src_rect.height,
 | 
	
		
			
				|  |  | -+      configDisplay.dest_rect.x_offset, configDisplay.dest_rect.y_offset, configDisplay.dest_rect.width, configDisplay.dest_rect.height, configDisplay.mode);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - int COMXVideo::GetInputBufferSize()
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXVideo.h b/xbmc/cores/omxplayer/OMXVideo.h
 | 
	
		
			
				|  |  | -index fd23e70..226000e 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXVideo.h
 | 
	
		
			
				|  |  | -@@ -32,6 +32,7 @@
 | 
	
		
			
				|  |  | - #include "DVDDemuxers/DVDDemux.h"
 | 
	
		
			
				|  |  | - #include "xbmc/settings/VideoSettings.h"
 | 
	
		
			
				|  |  | - #include "threads/CriticalSection.h"
 | 
	
		
			
				|  |  | -+#include "xbmc/rendering/RenderSystem.h"
 | 
	
		
			
				|  |  | - #include <string>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define VIDEO_BUFFERS 60
 | 
	
		
			
				|  |  | -@@ -58,7 +59,7 @@ class COMXVideo
 | 
	
		
			
				|  |  | -   void Reset(void);
 | 
	
		
			
				|  |  | -   void SetDropState(bool bDrop);
 | 
	
		
			
				|  |  | -   std::string GetDecoderName() { return m_video_codec_name; };
 | 
	
		
			
				|  |  | --  void SetVideoRect(const CRect& SrcRect, const CRect& DestRect);
 | 
	
		
			
				|  |  | -+  void SetVideoRect(const CRect& SrcRect, const CRect& DestRect, RENDER_STEREO_MODE video_mode, RENDER_STEREO_MODE display_mode);
 | 
	
		
			
				|  |  | -   int GetInputBufferSize();
 | 
	
		
			
				|  |  | -   void SubmitEOS();
 | 
	
		
			
				|  |  | -   bool IsEOS();
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 716400b7b3cf13c6546bba6a0d0a2f47825f9117 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 16 Apr 2014 21:18:06 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 72/94] [omxplayer] Don't propagate 3d flags based on supported
 | 
	
		
			
				|  |  | - 3d modes
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 29 ++++-------------------------
 | 
	
		
			
				|  |  | - 1 file changed, 4 insertions(+), 25 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index d5f3bec..e9f86f3 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -736,36 +736,15 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
 | 
	
		
			
				|  |  | -   unsigned flags = 0;
 | 
	
		
			
				|  |  | -   ERenderFormat format = RENDER_FMT_BYPASS;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  /* figure out steremode expected based on user settings and hints */
 | 
	
		
			
				|  |  | -+  unsigned int stereo_flags = GetStereoModeFlags(GetStereoMode());
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   if(m_bAllowFullscreen)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     flags |= CONF_FLAGS_FULLSCREEN;
 | 
	
		
			
				|  |  | -     m_bAllowFullscreen = false; // only allow on first configure
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  flags |= GetStereoModeFlags(GetStereoMode());
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if(flags & CONF_FLAGS_STEREO_MODE_SBS)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DSBS))
 | 
	
		
			
				|  |  | --      CLog::Log(LOGNOTICE, "3DSBS movie found");
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
 | 
	
		
			
				|  |  | --      CLog::Log(LOGNOTICE, "3DSBS movie found but not supported");
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else if(flags & CONF_FLAGS_STEREO_MODE_TAB)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    if(g_Windowing.Support3D(video_width, video_height, D3DPRESENTFLAG_MODE3DTB))
 | 
	
		
			
				|  |  | --      CLog::Log(LOGNOTICE, "3DTB movie found");
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      flags &= ~CONF_FLAGS_STEREO_MODE_MASK(~0);
 | 
	
		
			
				|  |  | --      CLog::Log(LOGNOTICE, "3DTB movie found but not supported");
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    CLog::Log(LOGNOTICE, "not a 3D movie");
 | 
	
		
			
				|  |  | -+  flags |= stereo_flags;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   unsigned int iDisplayWidth  = width;
 | 
	
		
			
				|  |  | -   unsigned int iDisplayHeight = height;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7f2220746d9efeb3e8cfc4524479a615db5b710c Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 17 Apr 2014 13:00:52 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 73/94] [graphics] Don't set stereo mode based on resolution
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -The resolution change should follow stereo mode
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.cpp | 22 ----------------------
 | 
	
		
			
				|  |  | - 1 file changed, 22 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -index 5bffdf5..7e4fdd4 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -@@ -418,28 +418,6 @@ void CGraphicContext::SetVideoResolution(RESOLUTION res, bool forceUpdate)
 | 
	
		
			
				|  |  | -   Lock();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   RESOLUTION_INFO info_org  = CDisplaySettings::Get().GetResolutionInfo(res);
 | 
	
		
			
				|  |  | --  RESOLUTION_INFO info_last = CDisplaySettings::Get().GetResolutionInfo(lastRes);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  RENDER_STEREO_MODE stereo_mode = m_stereoMode;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // if the new mode is an actual stereo mode, switch to that
 | 
	
		
			
				|  |  | --  // if the old mode was an actual stereo mode, switch to no 3d mode
 | 
	
		
			
				|  |  | --  if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DTB)
 | 
	
		
			
				|  |  | --    stereo_mode = RENDER_STEREO_MODE_SPLIT_HORIZONTAL;
 | 
	
		
			
				|  |  | --  else if (info_org.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
 | 
	
		
			
				|  |  | --    stereo_mode = RENDER_STEREO_MODE_SPLIT_VERTICAL;
 | 
	
		
			
				|  |  | --  else if ((info_last.dwFlags & D3DPRESENTFLAG_MODE3DSBS) != 0
 | 
	
		
			
				|  |  | --        || (info_last.dwFlags & D3DPRESENTFLAG_MODE3DTB)  != 0)
 | 
	
		
			
				|  |  | --    stereo_mode = RENDER_STEREO_MODE_OFF;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if(stereo_mode != m_stereoMode)
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_stereoView     = RENDER_STEREO_VIEW_OFF;
 | 
	
		
			
				|  |  | --    m_stereoMode     = stereo_mode;
 | 
	
		
			
				|  |  | --    m_nextStereoMode = stereo_mode;
 | 
	
		
			
				|  |  | --    CSettings::Get().SetInt("videoscreen.stereoscopicmode", (int)m_stereoMode);
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   RESOLUTION_INFO info_mod = GetResInfo(res);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_iScreenWidth  = info_mod.iWidth;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7885d90283809ccbcdb9c39809682dfc099049c4 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 17 Apr 2014 13:01:51 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 74/94] [graphics] Allow switching to a more suitable 3D
 | 
	
		
			
				|  |  | - resolution
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.cpp | 41 ++++++++++++++++++++++++++++++++++++++++-
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.h   |  1 +
 | 
	
		
			
				|  |  | - 2 files changed, 41 insertions(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -index 7e4fdd4..886b612 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -@@ -35,6 +35,7 @@
 | 
	
		
			
				|  |  | - #include "utils/JobManager.h"
 | 
	
		
			
				|  |  | - #include "video/VideoReferenceClock.h"
 | 
	
		
			
				|  |  | - #include "cores/IPlayer.h"
 | 
	
		
			
				|  |  | -+#include <float.h>
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - using namespace std;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -459,6 +460,44 @@ RESOLUTION CGraphicContext::GetVideoResolution() const
 | 
	
		
			
				|  |  | -   return m_Resolution;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+RESOLUTION CGraphicContext::Get3DVideoResolution(RENDER_STEREO_MODE mode) const
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  RESOLUTION best = m_Resolution;
 | 
	
		
			
				|  |  | -+  RESOLUTION_INFO curr = CDisplaySettings::Get().GetResolutionInfo(best);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // Find closest refresh rate
 | 
	
		
			
				|  |  | -+  for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    const RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo((RESOLUTION)i);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    //discard resolutions that are not the same width and height (and interlaced/3D flags)
 | 
	
		
			
				|  |  | -+    //or have a too low refreshrate
 | 
	
		
			
				|  |  | -+    if (info.iScreenWidth  != curr.iScreenWidth
 | 
	
		
			
				|  |  | -+    ||  info.iScreenHeight != curr.iScreenHeight
 | 
	
		
			
				|  |  | -+    ||  info.iScreen       != curr.iScreen
 | 
	
		
			
				|  |  | -+    ||  (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED)
 | 
	
		
			
				|  |  | -+    ||  fabs(info.fRefreshRate - curr.fRefreshRate) >= FLT_EPSILON)
 | 
	
		
			
				|  |  | -+      continue;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    if (mode == RENDER_STEREO_MODE_SPLIT_VERTICAL && info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      best = (RESOLUTION)i;
 | 
	
		
			
				|  |  | -+      break;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if (mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL && info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      best = (RESOLUTION)i;
 | 
	
		
			
				|  |  | -+      break;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if ((mode == RENDER_STEREO_MODE_OFF || mode == RENDER_STEREO_MODE_MONO) && !(info.dwFlags & (D3DPRESENTFLAG_MODE3DSBS|D3DPRESENTFLAG_MODE3DTB)))
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      best = (RESOLUTION)i;
 | 
	
		
			
				|  |  | -+      break;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  return best;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - void CGraphicContext::ResetOverscan(RESOLUTION_INFO &res)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   res.Overscan.left = 0;
 | 
	
		
			
				|  |  | -@@ -996,7 +1035,7 @@ void CGraphicContext::Flip(const CDirtyRegionList& dirty)
 | 
	
		
			
				|  |  | -   if(m_stereoMode != m_nextStereoMode)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     m_stereoMode = m_nextStereoMode;
 | 
	
		
			
				|  |  | --    SetVideoResolution(GetVideoResolution(), true);
 | 
	
		
			
				|  |  | -+    SetVideoResolution(Get3DVideoResolution(m_stereoMode), true);
 | 
	
		
			
				|  |  | -     g_windowManager.SendMessage(GUI_MSG_NOTIFY_ALL, 0, 0, GUI_MSG_RENDERER_RESET);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -index 0a27643..df55e92 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -@@ -108,6 +108,7 @@ class CGraphicContext : public CCriticalSection,
 | 
	
		
			
				|  |  | -   bool IsValidResolution(RESOLUTION res);
 | 
	
		
			
				|  |  | -   void SetVideoResolution(RESOLUTION res, bool forceUpdate = false);
 | 
	
		
			
				|  |  | -   RESOLUTION GetVideoResolution() const;
 | 
	
		
			
				|  |  | -+  RESOLUTION Get3DVideoResolution(RENDER_STEREO_MODE mode) const;
 | 
	
		
			
				|  |  | -   void ResetOverscan(RESOLUTION res, OVERSCAN &overscan);
 | 
	
		
			
				|  |  | -   void ResetOverscan(RESOLUTION_INFO &resinfo);
 | 
	
		
			
				|  |  | -   void ResetScreenParameters(RESOLUTION res);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 49438256c57d11b415f6a90f653857e7fae16a1d Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Thu, 17 Apr 2014 13:38:55 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 75/94] [3D] Support switching to 3D resolutions
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Include matching 3D flags (SBS/TAB) in the score of a resolution to switch to, to enable switching to 3d modes.
 | 
	
		
			
				|  |  | -Also remove the old code that treated 3D modes differently when assigning a score.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/BaseRenderer.cpp | 47 +++++++++++-------------------
 | 
	
		
			
				|  |  | - 1 file changed, 17 insertions(+), 30 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
 | 
	
		
			
				|  |  | -index 970b822..9ca1be1 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
 | 
	
		
			
				|  |  | -@@ -222,10 +222,14 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
 | 
	
		
			
				|  |  | - RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RESOLUTION current, float& weight)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   RESOLUTION_INFO curr = g_graphicsContext.GetResInfo(current);
 | 
	
		
			
				|  |  | -+  RENDER_STEREO_MODE stereo_mode = g_graphicsContext.GetStereoMode();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   float fRefreshRate = fps;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  float last_diff = fRefreshRate;
 | 
	
		
			
				|  |  | -+  int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
 | 
	
		
			
				|  |  | -+  if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ||
 | 
	
		
			
				|  |  | -+      !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(curr.dwFlags & D3DPRESENTFLAG_MODE3DTB))
 | 
	
		
			
				|  |  | -+    c_weight += 1000;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // Find closest refresh rate
 | 
	
		
			
				|  |  | -   for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
 | 
	
		
			
				|  |  | -@@ -241,40 +245,23 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES
 | 
	
		
			
				|  |  | -     ||  info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
 | 
	
		
			
				|  |  | -       continue;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    // For 3D choose the closest refresh rate 
 | 
	
		
			
				|  |  | --    if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      float diff = (info.fRefreshRate - fRefreshRate);
 | 
	
		
			
				|  |  | --      if(diff < 0)
 | 
	
		
			
				|  |  | --        diff *= -1.0f;
 | 
	
		
			
				|  |  | -+    int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      if(diff < last_diff)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        last_diff = diff;
 | 
	
		
			
				|  |  | --        current = (RESOLUTION)i;
 | 
	
		
			
				|  |  | --        curr = info;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    else
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      int c_weight = MathUtils::round_int(RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
 | 
	
		
			
				|  |  | --      int i_weight = MathUtils::round_int(RefreshWeight(info.fRefreshRate, fRefreshRate * multiplier) * 1000.0);
 | 
	
		
			
				|  |  | -+    if (!(stereo_mode == RENDER_STEREO_MODE_SPLIT_VERTICAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) ||
 | 
	
		
			
				|  |  | -+        !(stereo_mode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL) != !(info.dwFlags & D3DPRESENTFLAG_MODE3DTB))
 | 
	
		
			
				|  |  | -+      i_weight += 1000;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      // Closer the better, prefer higher refresh rate if the same
 | 
	
		
			
				|  |  | --      if ((i_weight <  c_weight)
 | 
	
		
			
				|  |  | --      ||  (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        current = (RESOLUTION)i;
 | 
	
		
			
				|  |  | --        curr    = info;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | -+    // Closer the better, prefer higher refresh rate if the same
 | 
	
		
			
				|  |  | -+    if ((i_weight <  c_weight)
 | 
	
		
			
				|  |  | -+    ||  (i_weight == c_weight && info.fRefreshRate > curr.fRefreshRate))
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      current  = (RESOLUTION)i;
 | 
	
		
			
				|  |  | -+      curr     = info;
 | 
	
		
			
				|  |  | -+      c_weight = i_weight;
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  // For 3D overwrite weight
 | 
	
		
			
				|  |  | --  if(CONF_FLAGS_STEREO_MODE_MASK(m_iFlags))
 | 
	
		
			
				|  |  | --    weight = 0;
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);
 | 
	
		
			
				|  |  | -+  weight = RefreshWeight(curr.fRefreshRate, fRefreshRate * multiplier);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   return current;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From bd077947037288550a8e68efed630a3477a16564 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 23 Apr 2014 00:05:07 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 76/94] [graphics] Make pixel ratio for 3d modes consistent
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Note: Use the stored stereo flags from lists of resolutions.
 | 
	
		
			
				|  |  | -Use current stereo mode for current resolution.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/BaseRenderer.cpp      | 10 ++++----
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.cpp                  | 32 ++++++++++---------------
 | 
	
		
			
				|  |  | - xbmc/guilib/GraphicContext.h                    |  4 ++--
 | 
	
		
			
				|  |  | - xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp |  8 -------
 | 
	
		
			
				|  |  | - 4 files changed, 19 insertions(+), 35 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/BaseRenderer.cpp b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
 | 
	
		
			
				|  |  | -index 9ca1be1..6bf42bf 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/BaseRenderer.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/BaseRenderer.cpp
 | 
	
		
			
				|  |  | -@@ -119,7 +119,7 @@ bool CBaseRenderer::FindResolutionFromOverride(float fps, float& weight, bool fa
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     for (size_t j = (int)RES_DESKTOP; j < CDisplaySettings::Get().ResolutionInfoSize(); j++)
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | --      RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j);
 | 
	
		
			
				|  |  | -+      RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)j, false);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       if (info.iScreenWidth  == curr.iScreenWidth
 | 
	
		
			
				|  |  | -        && info.iScreenHeight == curr.iScreenHeight
 | 
	
		
			
				|  |  | -@@ -179,7 +179,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
 | 
	
		
			
				|  |  | -       //get the resolution with the refreshrate closest to 60 hertz
 | 
	
		
			
				|  |  | -       for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
 | 
	
		
			
				|  |  | -+        RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         if (MathUtils::round_int(info.fRefreshRate) == 60
 | 
	
		
			
				|  |  | -          && info.iScreenWidth  == curr.iScreenWidth
 | 
	
		
			
				|  |  | -@@ -200,7 +200,7 @@ void CBaseRenderer::FindResolutionFromFpsMatch(float fps, float& weight)
 | 
	
		
			
				|  |  | -         CLog::Log(LOGDEBUG, "60 hertz refreshrate not available, choosing highest");
 | 
	
		
			
				|  |  | -         for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
 | 
	
		
			
				|  |  | -         {
 | 
	
		
			
				|  |  | --          RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
 | 
	
		
			
				|  |  | -+          RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -           if (info.fRefreshRate  >  curr.fRefreshRate
 | 
	
		
			
				|  |  | -            && info.iScreenWidth  == curr.iScreenWidth
 | 
	
		
			
				|  |  | -@@ -234,14 +234,14 @@ RESOLUTION CBaseRenderer::FindClosestResolution(float fps, float multiplier, RES
 | 
	
		
			
				|  |  | -   // Find closest refresh rate
 | 
	
		
			
				|  |  | -   for (size_t i = (int)RES_DESKTOP; i < CDisplaySettings::Get().ResolutionInfoSize(); i++)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i);
 | 
	
		
			
				|  |  | -+    const RESOLUTION_INFO info = g_graphicsContext.GetResInfo((RESOLUTION)i, false);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     //discard resolutions that are not the same width and height (and interlaced/3D flags)
 | 
	
		
			
				|  |  | -     //or have a too low refreshrate
 | 
	
		
			
				|  |  | -     if (info.iScreenWidth  != curr.iScreenWidth
 | 
	
		
			
				|  |  | -     ||  info.iScreenHeight != curr.iScreenHeight
 | 
	
		
			
				|  |  | -     ||  info.iScreen       != curr.iScreen
 | 
	
		
			
				|  |  | --    ||  (info.dwFlags & D3DPRESENTFLAG_MODEMASK) != (curr.dwFlags & D3DPRESENTFLAG_MODEMASK)
 | 
	
		
			
				|  |  | -+    ||  (info.dwFlags & D3DPRESENTFLAG_INTERLACED) != (curr.dwFlags & D3DPRESENTFLAG_INTERLACED)
 | 
	
		
			
				|  |  | -     ||  info.fRefreshRate < (fRefreshRate * multiplier / 1.001) - 0.001)
 | 
	
		
			
				|  |  | -       continue;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.cpp b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -index 886b612..40a6362 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.cpp
 | 
	
		
			
				|  |  | -@@ -707,32 +707,26 @@ void CGraphicContext::ApplyStateBlock()
 | 
	
		
			
				|  |  | -   g_Windowing.ApplyStateBlock();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const
 | 
	
		
			
				|  |  | -+const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res, bool use_current_3d /*= true*/) const
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   RESOLUTION_INFO info = CDisplaySettings::Get().GetResolutionInfo(res);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL)
 | 
	
		
			
				|  |  | -+  if(use_current_3d ? m_stereoMode == RENDER_STEREO_MODE_SPLIT_HORIZONTAL : (info.dwFlags & D3DPRESENTFLAG_MODE3DTB))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if((info.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      info.fPixelRatio     /= 2;
 | 
	
		
			
				|  |  | --      info.iBlanking        = 0;
 | 
	
		
			
				|  |  | --      info.dwFlags         |= D3DPRESENTFLAG_MODE3DTB;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    info.fPixelRatio     /= 2;
 | 
	
		
			
				|  |  | -+    info.iBlanking        = 0;
 | 
	
		
			
				|  |  | -+    info.dwFlags         |= D3DPRESENTFLAG_MODE3DTB;
 | 
	
		
			
				|  |  | -     info.iHeight          = (info.iHeight         - info.iBlanking) / 2;
 | 
	
		
			
				|  |  | -     info.Overscan.top    /= 2;
 | 
	
		
			
				|  |  | -     info.Overscan.bottom  = (info.Overscan.bottom - info.iBlanking) / 2;
 | 
	
		
			
				|  |  | -     info.iSubtitles       = (info.iSubtitles      - info.iBlanking) / 2;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if(m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL)
 | 
	
		
			
				|  |  | -+  if(use_current_3d ? m_stereoMode == RENDER_STEREO_MODE_SPLIT_VERTICAL : (info.dwFlags & D3DPRESENTFLAG_MODE3DSBS))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if((info.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      info.fPixelRatio     *= 2;
 | 
	
		
			
				|  |  | --      info.iBlanking        = 0;
 | 
	
		
			
				|  |  | --      info.dwFlags         |= D3DPRESENTFLAG_MODE3DSBS;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | -+    info.fPixelRatio     *= 2;
 | 
	
		
			
				|  |  | -+    info.iBlanking        = 0;
 | 
	
		
			
				|  |  | -+    info.dwFlags         |= D3DPRESENTFLAG_MODE3DSBS;
 | 
	
		
			
				|  |  | -     info.iWidth           = (info.iWidth         - info.iBlanking) / 2;
 | 
	
		
			
				|  |  | -     info.Overscan.left   /= 2;
 | 
	
		
			
				|  |  | -     info.Overscan.right   = (info.Overscan.right - info.iBlanking) / 2;
 | 
	
		
			
				|  |  | -@@ -740,7 +734,7 @@ const RESOLUTION_INFO CGraphicContext::GetResInfo(RESOLUTION res) const
 | 
	
		
			
				|  |  | -   return info;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info)
 | 
	
		
			
				|  |  | -+void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info, bool use_current_3d /*= true*/)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   RESOLUTION_INFO& curr = CDisplaySettings::Get().GetResolutionInfo(res);
 | 
	
		
			
				|  |  | -   curr.Overscan   = info.Overscan;
 | 
	
		
			
				|  |  | -@@ -750,16 +744,14 @@ void CGraphicContext::SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info)
 | 
	
		
			
				|  |  | -   if(info.dwFlags & D3DPRESENTFLAG_MODE3DSBS)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     curr.Overscan.right  = info.Overscan.right  * 2 + info.iBlanking;
 | 
	
		
			
				|  |  | --    if((curr.dwFlags & D3DPRESENTFLAG_MODE3DSBS) == 0)
 | 
	
		
			
				|  |  | --      curr.fPixelRatio  /= 2.0;
 | 
	
		
			
				|  |  | -+    curr.fPixelRatio  /= 2.0;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(info.dwFlags & D3DPRESENTFLAG_MODE3DTB)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     curr.Overscan.bottom = info.Overscan.bottom * 2 + info.iBlanking;
 | 
	
		
			
				|  |  | -     curr.iSubtitles      = info.iSubtitles      * 2 + info.iBlanking;
 | 
	
		
			
				|  |  | --    if((curr.dwFlags & D3DPRESENTFLAG_MODE3DTB) == 0)
 | 
	
		
			
				|  |  | --      curr.fPixelRatio  *= 2.0;
 | 
	
		
			
				|  |  | -+    curr.fPixelRatio  *= 2.0;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/guilib/GraphicContext.h b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -index df55e92..c77f2ff 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/guilib/GraphicContext.h
 | 
	
		
			
				|  |  | -@@ -124,8 +124,8 @@ class CGraphicContext : public CCriticalSection,
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     return GetResInfo(m_Resolution);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | --  const RESOLUTION_INFO GetResInfo(RESOLUTION res) const;
 | 
	
		
			
				|  |  | --  void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info);
 | 
	
		
			
				|  |  | -+  const RESOLUTION_INFO GetResInfo(RESOLUTION res, bool use_current_3d = true) const;
 | 
	
		
			
				|  |  | -+  void SetResInfo(RESOLUTION res, const RESOLUTION_INFO& info, bool use_current_3d = true);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   /* \brief Get UI scaling information from a given resolution to the screen resolution.
 | 
	
		
			
				|  |  | -    Takes account of overscan and UI zooming.
 | 
	
		
			
				|  |  | -diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -index 21b8cc4..f57b22b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -@@ -446,15 +446,9 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
 | 
	
		
			
				|  |  | -       m_desktopRes.fPixelRatio  = get_display_aspect_ratio((HDMI_ASPECT_T)tv_state.display.hdmi.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
 | 
	
		
			
				|  |  | -       // Also add 3D flags
 | 
	
		
			
				|  |  | -       if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_SBS_HALF)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | -         m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
 | 
	
		
			
				|  |  | --        m_desktopRes.fPixelRatio *= 2.0;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | -       else if (tv_state.display.hdmi.format_3d == HDMI_3D_FORMAT_TB_HALF)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | -         m_desktopRes.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
 | 
	
		
			
				|  |  | --        m_desktopRes.fPixelRatio *= 0.5;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | -       HDMI_PROPERTY_PARAM_T property;
 | 
	
		
			
				|  |  | -       property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
 | 
	
		
			
				|  |  | -       vc_tv_hdmi_get_property(&property);
 | 
	
		
			
				|  |  | -@@ -605,7 +599,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -         res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
 | 
	
		
			
				|  |  | -         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
 | 
	
		
			
				|  |  | --        res2.fPixelRatio   *= 2.0f;
 | 
	
		
			
				|  |  | -         SetResolutionString(res2);
 | 
	
		
			
				|  |  | -         CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -623,7 +616,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -         res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
 | 
	
		
			
				|  |  | -         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
 | 
	
		
			
				|  |  | --        res2.fPixelRatio   *= 0.5f;
 | 
	
		
			
				|  |  | -         SetResolutionString(res2);
 | 
	
		
			
				|  |  | -         CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7464b116a5db0be0c2b50314fcf703529d6f646e Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 23 Apr 2014 21:07:51 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 77/94] [PiSink] More attempts to reduce underrun audio
 | 
	
		
			
				|  |  | - glitches with multichannl and high samplerate
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp | 79 +++++++++++--------------------
 | 
	
		
			
				|  |  | - 1 file changed, 27 insertions(+), 52 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
 | 
	
		
			
				|  |  | -index 070e6eb..133b9f6 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/AudioEngine/Sinks/AESinkPi.cpp
 | 
	
		
			
				|  |  | -@@ -186,7 +186,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
 | 
	
		
			
				|  |  | -   unsigned int sample_size = CAEUtil::DataFormatToBits(format.m_dataFormat) >> 3;
 | 
	
		
			
				|  |  | -   format.m_frameSize     = sample_size * channels;
 | 
	
		
			
				|  |  | -   format.m_sampleRate    = std::max(8000U, std::min(192000U, format.m_sampleRate));
 | 
	
		
			
				|  |  | --  format.m_frames        = format.m_sampleRate * AUDIO_PLAYBUFFER;
 | 
	
		
			
				|  |  | -+  format.m_frames        = format.m_sampleRate * AUDIO_PLAYBUFFER / NUM_OMX_BUFFERS;
 | 
	
		
			
				|  |  | -   format.m_frameSamples  = format.m_frames * channels;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   SetAudioProps(m_passthrough, GetChannelMap(format.m_channelLayout, m_passthrough));
 | 
	
		
			
				|  |  | -@@ -232,7 +232,7 @@ bool CAESinkPi::Initialize(AEAudioFormat &format, std::string &device)
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "%s:%s - error get OMX_IndexParamPortDefinition (input) omx_err(0x%08x)", CLASSNAME, __func__, omx_err);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   port_param.nBufferCountActual = std::max((unsigned int)port_param.nBufferCountMin, (unsigned int)NUM_OMX_BUFFERS);
 | 
	
		
			
				|  |  | --  port_param.nBufferSize = m_format.m_frameSize * m_format.m_frames / port_param.nBufferCountActual;
 | 
	
		
			
				|  |  | -+  port_param.nBufferSize = m_format.m_frameSize * m_format.m_frames;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   omx_err = m_omx_render.SetParameter(OMX_IndexParamPortDefinition, &port_param);
 | 
	
		
			
				|  |  | -   if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -@@ -308,63 +308,38 @@ double CAESinkPi::GetCacheTotal()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - unsigned int CAESinkPi::AddPackets(uint8_t *data, unsigned int frames, bool hasAudio, bool blocking)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  unsigned int sent = 0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if (!m_Initialized)
 | 
	
		
			
				|  |  | -+  if (!m_Initialized || !frames)
 | 
	
		
			
				|  |  | -     return frames;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
 | 
	
		
			
				|  |  | -   OMX_BUFFERHEADERTYPE *omx_buffer = NULL;
 | 
	
		
			
				|  |  | --  while (sent < frames)
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  double delay = GetDelay();
 | 
	
		
			
				|  |  | -+  if (delay <= 0.0 && m_submitted)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGNOTICE, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_buffer = m_omx_render.GetInputBuffer(1000);
 | 
	
		
			
				|  |  | -+  if (omx_buffer == NULL)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    double delay = GetDelay();
 | 
	
		
			
				|  |  | --    double ideal_submission_time = AUDIO_PLAYBUFFER - delay;
 | 
	
		
			
				|  |  | --    // ideal amount of audio we'd like submit (to make delay match AUDIO_PLAYBUFFER)
 | 
	
		
			
				|  |  | --    int timeout = blocking ? 1000 : 0;
 | 
	
		
			
				|  |  | --    int ideal_submission_samples = ideal_submission_time / (m_sinkbuffer_sec_per_byte * m_format.m_frameSize);
 | 
	
		
			
				|  |  | --    // if we are almost full then sleep (to avoid repeatedly sending a few samples)
 | 
	
		
			
				|  |  | --    bool too_laggy = ideal_submission_time < 0.25 * AUDIO_PLAYBUFFER;
 | 
	
		
			
				|  |  | --    int sleeptime = (int)(AUDIO_PLAYBUFFER * 0.25 * 1000.0);
 | 
	
		
			
				|  |  | --    if (too_laggy)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      if (blocking)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        Sleep(sleeptime);
 | 
	
		
			
				|  |  | --        continue;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    omx_buffer = m_omx_render.GetInputBuffer(timeout);
 | 
	
		
			
				|  |  | --    if (omx_buffer == NULL)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      if (blocking)
 | 
	
		
			
				|  |  | --        CLog::Log(LOGERROR, "COMXAudio::Decode timeout");
 | 
	
		
			
				|  |  | --      break;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    unsigned int space = omx_buffer->nAllocLen / m_format.m_frameSize;
 | 
	
		
			
				|  |  | --    unsigned int samples = std::min(std::min(space, (unsigned int)ideal_submission_samples), frames - sent);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_buffer->nFilledLen = samples * m_format.m_frameSize;
 | 
	
		
			
				|  |  | --    omx_buffer->nTimeStamp = ToOMXTime(0);
 | 
	
		
			
				|  |  | --    omx_buffer->nFlags = 0;
 | 
	
		
			
				|  |  | --    memcpy(omx_buffer->pBuffer, (uint8_t *)data + sent * m_format.m_frameSize, omx_buffer->nFilledLen);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    sent += samples;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (sent == frames)
 | 
	
		
			
				|  |  | --      omx_buffer->nFlags |= OMX_BUFFERFLAG_ENDOFFRAME;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if (delay <= 0.0 && m_submitted)
 | 
	
		
			
				|  |  | --      CLog::Log(LOGNOTICE, "%s:%s Underrun (delay:%.2f frames:%d)", CLASSNAME, __func__, delay, frames);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    omx_err = m_omx_render.EmptyThisBuffer(omx_buffer);
 | 
	
		
			
				|  |  | --    if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | --      CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err);
 | 
	
		
			
				|  |  | --    m_submitted++;
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "CAESinkPi::AddPackets timeout");
 | 
	
		
			
				|  |  | -+    return 0;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  return sent;
 | 
	
		
			
				|  |  | -+  omx_buffer->nFilledLen = frames * m_format.m_frameSize;
 | 
	
		
			
				|  |  | -+  // must be true
 | 
	
		
			
				|  |  | -+  assert(omx_buffer->nFilledLen <= omx_buffer->nAllocLen);
 | 
	
		
			
				|  |  | -+  omx_buffer->nTimeStamp = ToOMXTime(0);
 | 
	
		
			
				|  |  | -+  omx_buffer->nFlags = OMX_BUFFERFLAG_ENDOFFRAME;
 | 
	
		
			
				|  |  | -+  memcpy(omx_buffer->pBuffer, data, omx_buffer->nFilledLen);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  omx_err = m_omx_render.EmptyThisBuffer(omx_buffer);
 | 
	
		
			
				|  |  | -+  if (omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGERROR, "%s:%s frames=%d err=%x", CLASSNAME, __func__, frames, omx_err);
 | 
	
		
			
				|  |  | -+  m_submitted++;
 | 
	
		
			
				|  |  | -+  delay = GetDelay();
 | 
	
		
			
				|  |  | -+  if (delay > AUDIO_PLAYBUFFER)
 | 
	
		
			
				|  |  | -+    Sleep((int)(1000.0f * (delay - AUDIO_PLAYBUFFER)));
 | 
	
		
			
				|  |  | -+  return frames;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CAESinkPi::Drain()
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 508c32de290d09c429d73b2497408b930550f1a3 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 23 Apr 2014 22:36:01 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 78/94] [omxplayer] Fix for aspect ratio of portrait videos
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 10 ++++++++++
 | 
	
		
			
				|  |  | - 1 file changed, 10 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index e9f86f3..7e2c644 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -651,6 +651,16 @@ void OMXPlayerVideo::SetVideoRect(const CRect &InSrcRect, const CRect &InDestRec
 | 
	
		
			
				|  |  | -   bool stereo_invert                   = (flags & CONF_FLAGS_STEREO_CADANCE_RIGHT_LEFT) ? true : false;
 | 
	
		
			
				|  |  | -   RENDER_STEREO_MODE display_stereo_mode = g_graphicsContext.GetStereoMode();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  // fix up transposed video
 | 
	
		
			
				|  |  | -+  if (m_hints.orientation == 90 || m_hints.orientation == 270)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    float diff = (DestRect.Height() - DestRect.Width()) * 0.5f;
 | 
	
		
			
				|  |  | -+    DestRect.x1 -= diff;
 | 
	
		
			
				|  |  | -+    DestRect.x2 += diff;
 | 
	
		
			
				|  |  | -+    DestRect.y1 += diff;
 | 
	
		
			
				|  |  | -+    DestRect.y2 -= diff;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // check if destination rect or video view mode has changed
 | 
	
		
			
				|  |  | -   if (!(m_dst_rect != DestRect) && !(m_src_rect != SrcRect) && m_video_stereo_mode == video_stereo_mode && m_display_stereo_mode == display_stereo_mode && m_StereoInvert == stereo_invert)
 | 
	
		
			
				|  |  | -     return;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From fe9fea7a1aac545aa601b71aae01651bc42a5376 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Tue, 22 Apr 2014 12:23:23 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 79/94] [omxplayer] Make dvdplayer the default for dvd images
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/omxplayer_advancedsettings.xml | 2 +-
 | 
	
		
			
				|  |  | - 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml
 | 
	
		
			
				|  |  | -index 77c6a15..51c0daf 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/omxplayer_advancedsettings.xml
 | 
	
		
			
				|  |  | -@@ -2,6 +2,6 @@
 | 
	
		
			
				|  |  | - <advancedsettings>
 | 
	
		
			
				|  |  | -   <video>
 | 
	
		
			
				|  |  | -     <defaultplayer>omxplayer</defaultplayer>
 | 
	
		
			
				|  |  | --    <defaultdvdplayer>omxplayer</defaultdvdplayer>
 | 
	
		
			
				|  |  | -+    <defaultdvdplayer>dvdplayer</defaultdvdplayer>
 | 
	
		
			
				|  |  | -   </video>
 | 
	
		
			
				|  |  | - </advancedsettings>
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From f417d7d303eaa5113edba8ba562cb61ed8a6c59a Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 26 Apr 2014 17:27:52 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 80/94] [cec] Don't suspend pi on tv switch off - it can't wake
 | 
	
		
			
				|  |  | - up
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - system/peripherals.xml | 2 +-
 | 
	
		
			
				|  |  | - 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/system/peripherals.xml b/system/peripherals.xml
 | 
	
		
			
				|  |  | -index a906628..9b5271a 100644
 | 
	
		
			
				|  |  | ---- a/system/peripherals.xml
 | 
	
		
			
				|  |  | -+++ b/system/peripherals.xml
 | 
	
		
			
				|  |  | -@@ -16,7 +16,7 @@
 | 
	
		
			
				|  |  | -     <setting key="send_inactive_source" type="bool" value="1" label="36025" order="5" />
 | 
	
		
			
				|  |  | -     <setting key="cec_standby_screensaver" type="bool" value="0" label="36009" order="6" />
 | 
	
		
			
				|  |  | -     <setting key="cec_wake_screensaver" type="bool" value="1" label="36010" order="7" />
 | 
	
		
			
				|  |  | --    <setting key="standby_pc_on_tv_standby" type="enum" value="13011" label="36029" order="8" lvalues="36028|13005|13011" />
 | 
	
		
			
				|  |  | -+    <setting key="standby_pc_on_tv_standby" type="enum" value="36028" label="36029" order="8" lvalues="36028|13005|13011" />
 | 
	
		
			
				|  |  | -     <setting key="standby_tv_on_pc_standby" type="bool" value="1" label="36026" order="9" />
 | 
	
		
			
				|  |  | -     <setting key="use_tv_menu_language" type="bool" value="1" label="36018" order="10" />
 | 
	
		
			
				|  |  | -     <setting key="pause_playback_on_deactivate" type="bool" value="1" label="36033" order="11" />
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 0563f1df1295ac5600fd330fb201e854ad900e02 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 12 Apr 2014 17:57:19 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 81/94] [omxplayer] Ignore occasionally valid pts values, they
 | 
	
		
			
				|  |  | - cause live tv stutter
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 2 +-
 | 
	
		
			
				|  |  | - 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index 7e2c644..b3786f6 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -490,7 +490,7 @@ void OMXPlayerVideo::Process()
 | 
	
		
			
				|  |  | -         // if a stream has had more than 4 valid pts values in the last 16, the use UNKNOWN, otherwise use dts
 | 
	
		
			
				|  |  | -         m_history_valid_pts = (m_history_valid_pts << 1) | (pPacket->pts != DVD_NOPTS_VALUE);
 | 
	
		
			
				|  |  | -         double pts = pPacket->pts;
 | 
	
		
			
				|  |  | --        if(pPacket->pts == DVD_NOPTS_VALUE && count_bits(m_history_valid_pts & 0xffff) < 4)
 | 
	
		
			
				|  |  | -+        if(count_bits(m_history_valid_pts & 0xffff) < 4)
 | 
	
		
			
				|  |  | -           pts = pPacket->dts;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         if (pts != DVD_NOPTS_VALUE)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From cddc5f27f9aa11dfb65e16ec1f84a809cf79c68b Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 7 May 2014 14:54:41 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 82/94] [Pi] Fix naming of refresh rates to avoid lost
 | 
	
		
			
				|  |  | - calibration settings
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 13 ++++---------
 | 
	
		
			
				|  |  | - xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h   |  2 +-
 | 
	
		
			
				|  |  | - 2 files changed, 5 insertions(+), 10 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -index f57b22b..5b26b20 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -@@ -58,6 +58,7 @@
 | 
	
		
			
				|  |  | - # define DLOG(fmt, args...)
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+static void SetResolutionString(RESOLUTION_INFO &res);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - CEGLNativeTypeRaspberryPI::CEGLNativeTypeRaspberryPI()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -@@ -194,8 +195,9 @@ int CEGLNativeTypeRaspberryPI::FindMatchingResolution(const RESOLUTION_INFO &res
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(TARGET_RASPBERRY_PI)
 | 
	
		
			
				|  |  | --int CEGLNativeTypeRaspberryPI::AddUniqueResolution(const RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions)
 | 
	
		
			
				|  |  | -+int CEGLNativeTypeRaspberryPI::AddUniqueResolution(RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -+  SetResolutionString(res);
 | 
	
		
			
				|  |  | -   int i = FindMatchingResolution(res, resolutions);
 | 
	
		
			
				|  |  | -   if (i>=0)
 | 
	
		
			
				|  |  | -   {  // don't replace a progressive resolution with an interlaced one of same resolution
 | 
	
		
			
				|  |  | -@@ -467,10 +469,7 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
 | 
	
		
			
				|  |  | -       m_desktopRes.fPixelRatio  = get_display_aspect_ratio((SDTV_ASPECT_T)tv_state.display.sdtv.display_options.aspect) / ((float)m_desktopRes.iScreenWidth / (float)m_desktopRes.iScreenHeight);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    m_desktopRes.strMode = StringUtils::Format("%dx%d", m_desktopRes.iScreenWidth, m_desktopRes.iScreenHeight);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --    if((int)m_desktopRes.fRefreshRate > 1)
 | 
	
		
			
				|  |  | --      SetResolutionString(m_desktopRes);
 | 
	
		
			
				|  |  | -+    SetResolutionString(m_desktopRes);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     m_initDesktopRes = false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -578,8 +577,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -       res.iScreenHeight = tv->height;
 | 
	
		
			
				|  |  | -       res.fPixelRatio   = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res.iScreenWidth / (float)res.iScreenHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      SetResolutionString(res);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -       CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) %s%s:%x\n", i, res.strMode.c_str(), res.fPixelRatio,
 | 
	
		
			
				|  |  | -           tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -599,7 +596,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -         res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
 | 
	
		
			
				|  |  | -         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
 | 
	
		
			
				|  |  | --        SetResolutionString(res2);
 | 
	
		
			
				|  |  | -         CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
 | 
	
		
			
				|  |  | -@@ -616,7 +612,6 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -         res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
 | 
	
		
			
				|  |  | -         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
 | 
	
		
			
				|  |  | --        SetResolutionString(res2);
 | 
	
		
			
				|  |  | -         CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
 | 
	
		
			
				|  |  | -diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
 | 
	
		
			
				|  |  | -index d1ebb81..59401f5 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.h
 | 
	
		
			
				|  |  | -@@ -71,6 +71,6 @@ class CEGLNativeTypeRaspberryPI : public CEGLNativeType
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   void DestroyDispmaxWindow();
 | 
	
		
			
				|  |  | -   int FindMatchingResolution(const RESOLUTION_INFO &res, const std::vector<RESOLUTION_INFO> &resolutions);
 | 
	
		
			
				|  |  | --  int AddUniqueResolution(const RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions);
 | 
	
		
			
				|  |  | -+  int AddUniqueResolution(RESOLUTION_INFO &res, std::vector<RESOLUTION_INFO> &resolutions);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From a4c36a4925e780b63d9821fb04504453ac982205 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 10 May 2014 11:40:41 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 83/94] [omxplayer] Skip out of submit loop when closing.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Avoids a permanent hang at EOF when using IPTV streams
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerAudio.cpp | 7 +++++--
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerAudio.h   | 1 +
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 7 +++++--
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.h   | 1 +
 | 
	
		
			
				|  |  | - 4 files changed, 12 insertions(+), 4 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -index d3348ec..4435d22 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.cpp
 | 
	
		
			
				|  |  | -@@ -89,6 +89,7 @@ OMXPlayerAudio::OMXPlayerAudio(OMXClock *av_clock, CDVDMessageQueue& parent)
 | 
	
		
			
				|  |  | -   m_hw_decode = false;
 | 
	
		
			
				|  |  | -   m_silence = false;
 | 
	
		
			
				|  |  | -   m_flush = false;  
 | 
	
		
			
				|  |  | -+  m_bClose = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -145,11 +146,13 @@ void OMXPlayerAudio::OpenStream(CDVDStreamInfo &hints, COMXAudioCodecOMX *codec)
 | 
	
		
			
				|  |  | -   m_format.m_dataFormat    = GetDataFormat(m_hints);
 | 
	
		
			
				|  |  | -   m_format.m_sampleRate    = 0;
 | 
	
		
			
				|  |  | -   m_format.m_channelLayout = 0;
 | 
	
		
			
				|  |  | -+  m_bClose = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - bool OMXPlayerAudio::CloseStream(bool bWaitForBuffers)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   // wait until buffers are empty
 | 
	
		
			
				|  |  | -+  m_bClose = true;
 | 
	
		
			
				|  |  | -   if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_messageQueue.Abort();
 | 
	
		
			
				|  |  | -@@ -259,8 +262,8 @@ bool OMXPlayerAudio::Decode(DemuxPacket *pkt, bool bDropPacket)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       while(!m_bStop)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        // discard if flushing as clocks may be stopped and we'll never submit it
 | 
	
		
			
				|  |  | --        if(m_flush)
 | 
	
		
			
				|  |  | -+        // discard if flushing or closing as clocks may be stopped and we'll never submit it
 | 
	
		
			
				|  |  | -+        if(m_flush || m_bClose)
 | 
	
		
			
				|  |  | -           break;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         if(m_omxAudio.GetSpace() < (unsigned int)decoded_size)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerAudio.h b/xbmc/cores/omxplayer/OMXPlayerAudio.h
 | 
	
		
			
				|  |  | -index 685a686..7b55e48 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerAudio.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerAudio.h
 | 
	
		
			
				|  |  | -@@ -70,6 +70,7 @@ class OMXPlayerAudio : public CThread
 | 
	
		
			
				|  |  | -   bool                      m_DecoderOpen;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool                      m_bad_state;
 | 
	
		
			
				|  |  | -+  bool                      m_bClose;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   virtual void OnStartup();
 | 
	
		
			
				|  |  | -   virtual void OnExit();
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index b3786f6..61b884e 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -104,6 +104,7 @@ OMXPlayerVideo::OMXPlayerVideo(OMXClock *av_clock,
 | 
	
		
			
				|  |  | -   m_iCurrentPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -   m_nextOverlay = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -   m_flush = false;
 | 
	
		
			
				|  |  | -+  m_bClose = false;
 | 
	
		
			
				|  |  | -   m_history_valid_pts = 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -118,6 +119,7 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints)
 | 
	
		
			
				|  |  | -   m_hdmi_clock_sync = (CSettings::Get().GetInt("videoplayer.adjustrefreshrate") != ADJUST_REFRESHRATE_OFF);
 | 
	
		
			
				|  |  | -   m_started     = false;
 | 
	
		
			
				|  |  | -   m_flush       = false;
 | 
	
		
			
				|  |  | -+  m_bClose      = false;
 | 
	
		
			
				|  |  | -   m_stalled     = m_messageQueue.GetPacketCount(CDVDMsg::DEMUXER_PACKET) == 0;
 | 
	
		
			
				|  |  | -   m_nextOverlay = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -   // force SetVideoRect to be called initially
 | 
	
		
			
				|  |  | -@@ -161,6 +163,7 @@ bool OMXPlayerVideo::OpenStream(CDVDStreamInfo &hints, COMXVideo *codec)
 | 
	
		
			
				|  |  | - bool OMXPlayerVideo::CloseStream(bool bWaitForBuffers)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   // wait until buffers are empty
 | 
	
		
			
				|  |  | -+  m_bClose = true;
 | 
	
		
			
				|  |  | -   if (bWaitForBuffers && m_speed > 0) m_messageQueue.WaitUntilEmpty();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_messageQueue.Abort();
 | 
	
		
			
				|  |  | -@@ -469,8 +472,8 @@ void OMXPlayerVideo::Process()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       while (!m_bStop)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | --        // discard if flushing as clocks may be stopped and we'll never submit it
 | 
	
		
			
				|  |  | --        if (m_flush)
 | 
	
		
			
				|  |  | -+        // discard if flushing or closing as clocks may be stopped and we'll never submit it
 | 
	
		
			
				|  |  | -+        if (m_flush || m_bClose)
 | 
	
		
			
				|  |  | -            break;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         if((int)m_omxVideo.GetFreeSpace() < pPacket->iSize)
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.h b/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -index 6f19395..8eff32f 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.h
 | 
	
		
			
				|  |  | -@@ -66,6 +66,7 @@ class OMXPlayerVideo : public CThread
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   float                     m_fForcedAspectRatio;
 | 
	
		
			
				|  |  | -   unsigned                  m_flags;
 | 
	
		
			
				|  |  | -+  bool                      m_bClose;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   CRect                     m_src_rect;
 | 
	
		
			
				|  |  | -   CRect                     m_dst_rect;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From b90562b8ffc29c1d9e037e94b0c92b3b0b67413b Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: xbmc <fernetmenta@online.de>
 | 
	
		
			
				|  |  | -Date: Mon, 28 May 2012 10:34:39 +0200
 | 
	
		
			
				|  |  | -Subject: [PATCH 84/94] videoplayer: adapt lateness detection and dropping to
 | 
	
		
			
				|  |  | - buffering
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/RenderManager.cpp        |  16 +-
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/RenderManager.h          |  12 +-
 | 
	
		
			
				|  |  | - .../dvdplayer/DVDCodecs/Video/DVDVideoCodec.h      |  38 +++-
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp        |  41 +++++
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecFFmpeg.h          |   7 +
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp            | 197 +++++++++++++++++----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDPlayerVideo.h              |  23 +++
 | 
	
		
			
				|  |  | - 7 files changed, 296 insertions(+), 38 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/RenderManager.cpp b/xbmc/cores/VideoRenderers/RenderManager.cpp
 | 
	
		
			
				|  |  | -index 3503988..4ca74f8 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/RenderManager.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/RenderManager.cpp
 | 
	
		
			
				|  |  | -@@ -286,6 +286,8 @@ bool CXBMCRenderManager::Configure(unsigned int width, unsigned int height, unsi
 | 
	
		
			
				|  |  | -     m_bIsStarted = true;
 | 
	
		
			
				|  |  | -     m_bReconfigured = true;
 | 
	
		
			
				|  |  | -     m_presentstep = PRESENT_IDLE;
 | 
	
		
			
				|  |  | -+    m_presentpts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -+    m_sleeptime = 1.0;
 | 
	
		
			
				|  |  | -     m_presentevent.notifyAll();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     m_firstFlipPage = false;  // tempfix
 | 
	
		
			
				|  |  | -@@ -629,7 +631,7 @@ void CXBMCRenderManager::SetViewMode(int iViewMode)
 | 
	
		
			
				|  |  | -     m_pRenderer->SetViewMode(iViewMode);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
 | 
	
		
			
				|  |  | -+void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0LL*/, double pts /* = 0 */, int source /*= -1*/, EFIELDSYNC sync /*= FS_NONE*/)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   { CSharedLock lock(m_sharedSection);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -697,6 +699,7 @@ void CXBMCRenderManager::FlipPage(volatile bool& bStop, double timestamp /* = 0L
 | 
	
		
			
				|  |  | -     m.timestamp     = timestamp;
 | 
	
		
			
				|  |  | -     m.presentfield  = sync;
 | 
	
		
			
				|  |  | -     m.presentmethod = presentmethod;
 | 
	
		
			
				|  |  | -+    m.pts           = pts;
 | 
	
		
			
				|  |  | -     requeue(m_queued, m_free);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     /* signal to any waiters to check state */
 | 
	
		
			
				|  |  | -@@ -1065,6 +1068,8 @@ void CXBMCRenderManager::PrepareNextRender()
 | 
	
		
			
				|  |  | -     m_discard.push_back(m_presentsource);
 | 
	
		
			
				|  |  | -     m_presentsource = idx;
 | 
	
		
			
				|  |  | -     m_queued.pop_front();
 | 
	
		
			
				|  |  | -+    m_sleeptime = m_Queue[idx].timestamp - clocktime;
 | 
	
		
			
				|  |  | -+    m_presentpts = m_Queue[idx].pts;
 | 
	
		
			
				|  |  | -     m_presentevent.notifyAll();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -@@ -1081,3 +1086,12 @@ void CXBMCRenderManager::DiscardBuffer()
 | 
	
		
			
				|  |  | -     m_presentstep   = PRESENT_IDLE;
 | 
	
		
			
				|  |  | -   m_presentevent.notifyAll();
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+bool CXBMCRenderManager::GetStats(double &sleeptime, double &pts, int &bufferLevel)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CSingleLock lock(m_presentlock);
 | 
	
		
			
				|  |  | -+  sleeptime = m_sleeptime;
 | 
	
		
			
				|  |  | -+  pts = m_presentpts;
 | 
	
		
			
				|  |  | -+  bufferLevel = m_queued.size() + m_discard.size();
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/RenderManager.h b/xbmc/cores/VideoRenderers/RenderManager.h
 | 
	
		
			
				|  |  | -index c469795..949c652b 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/RenderManager.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/RenderManager.h
 | 
	
		
			
				|  |  | -@@ -98,10 +98,11 @@ class CXBMCRenderManager
 | 
	
		
			
				|  |  | -    *
 | 
	
		
			
				|  |  | -    * @param bStop reference to stop flag of calling thread
 | 
	
		
			
				|  |  | -    * @param timestamp of frame delivered with AddVideoPicture
 | 
	
		
			
				|  |  | -+   * @param pts used for lateness detection
 | 
	
		
			
				|  |  | -    * @param source depreciated
 | 
	
		
			
				|  |  | -    * @param sync signals frame, top, or bottom field
 | 
	
		
			
				|  |  | -    */
 | 
	
		
			
				|  |  | --  void FlipPage(volatile bool& bStop, double timestamp = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
 | 
	
		
			
				|  |  | -+  void FlipPage(volatile bool& bStop, double timestamp = 0.0, double pts = 0.0, int source = -1, EFIELDSYNC sync = FS_NONE);
 | 
	
		
			
				|  |  | -   unsigned int PreInit();
 | 
	
		
			
				|  |  | -   void UnInit();
 | 
	
		
			
				|  |  | -   bool Flush();
 | 
	
		
			
				|  |  | -@@ -176,6 +177,12 @@ class CXBMCRenderManager
 | 
	
		
			
				|  |  | -   int WaitForBuffer(volatile bool& bStop, int timeout = 100);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   /**
 | 
	
		
			
				|  |  | -+   * Can be called by player for lateness detection. This is done best by
 | 
	
		
			
				|  |  | -+   * looking at the end of the queue.
 | 
	
		
			
				|  |  | -+   */
 | 
	
		
			
				|  |  | -+  bool GetStats(double &sleeptime, double &pts, int &bufferLevel);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  /**
 | 
	
		
			
				|  |  | -    * Video player call this on flush in oder to discard any queued frames
 | 
	
		
			
				|  |  | -    */
 | 
	
		
			
				|  |  | -   void DiscardBuffer();
 | 
	
		
			
				|  |  | -@@ -222,6 +229,7 @@ class CXBMCRenderManager
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   struct SPresent
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -+    double         pts;
 | 
	
		
			
				|  |  | -     double         timestamp;
 | 
	
		
			
				|  |  | -     EFIELDSYNC     presentfield;
 | 
	
		
			
				|  |  | -     EPRESENTMETHOD presentmethod;
 | 
	
		
			
				|  |  | -@@ -233,6 +241,8 @@ class CXBMCRenderManager
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   ERenderFormat   m_format;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  double     m_sleeptime;
 | 
	
		
			
				|  |  | -+  double     m_presentpts;
 | 
	
		
			
				|  |  | -   double     m_presentcorr;
 | 
	
		
			
				|  |  | -   double     m_presenterr;
 | 
	
		
			
				|  |  | -   double     m_errorbuff[ERRORBUFFSIZE];
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
 | 
	
		
			
				|  |  | -index dc047d7..c09939c 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodec.h
 | 
	
		
			
				|  |  | -@@ -129,6 +129,10 @@ struct DVDVideoUserData
 | 
	
		
			
				|  |  | - #define DVP_FLAG_NOSKIP             0x00000010 // indicate this picture should never be dropped
 | 
	
		
			
				|  |  | - #define DVP_FLAG_DROPPED            0x00000020 // indicate that this picture has been dropped in decoder stage, will have no data
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+#define DVP_FLAG_DROPDEINT          0x00000040 // indicate that this picture was requested to have been dropped in deint stage
 | 
	
		
			
				|  |  | -+#define DVP_FLAG_NO_POSTPROC        0x00000100 // see GetCodecStats
 | 
	
		
			
				|  |  | -+#define DVP_FLAG_DRAIN              0x00000200 // see GetCodecStats
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - // DVP_FLAG 0x00000100 - 0x00000f00 is in use by libmpeg2!
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define DVP_QSCALE_UNKNOWN          0
 | 
	
		
			
				|  |  | -@@ -146,6 +150,8 @@ class CDVDCodecOptions;
 | 
	
		
			
				|  |  | - #define VC_PICTURE  0x00000004  // the decoder got a picture, call Decode(NULL, 0) again to parse the rest of the data
 | 
	
		
			
				|  |  | - #define VC_USERDATA 0x00000008  // the decoder found some userdata,  call Decode(NULL, 0) again to parse the rest of the data
 | 
	
		
			
				|  |  | - #define VC_FLUSHED  0x00000010  // the decoder lost it's state, we need to restart decoding again
 | 
	
		
			
				|  |  | -+#define VC_DROPPED  0x00000020  // needed to identify if a picture was dropped
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - class CDVDVideoCodec
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -@@ -263,7 +269,6 @@ class CDVDVideoCodec
 | 
	
		
			
				|  |  | -     return 0;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   /**
 | 
	
		
			
				|  |  | -    * Number of references to old pictures that are allowed to
 | 
	
		
			
				|  |  | -    * be retained when calling decode on the next demux packet
 | 
	
		
			
				|  |  | -@@ -280,4 +285,35 @@ class CDVDVideoCodec
 | 
	
		
			
				|  |  | -   * Interact with user settings so that user disabled codecs are disabled
 | 
	
		
			
				|  |  | -   */
 | 
	
		
			
				|  |  | -   static bool IsCodecDisabled(DVDCodecAvailableType* map, unsigned int size, AVCodecID id);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+   /* For calculation of dropping requirements player asks for some information.
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   * - pts : right after decoder, used to detect gaps (dropped frames in decoder)
 | 
	
		
			
				|  |  | -+   * - droppedPics : indicates if decoder has dropped a picture
 | 
	
		
			
				|  |  | -+   *                 -1 means that decoder has no info on this.
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   * If codec does not implement this method, pts of decoded frame at input
 | 
	
		
			
				|  |  | -+   * video player is used. In case decoder does post-proc and de-interlacing there
 | 
	
		
			
				|  |  | -+   * may be quite some frames queued up between exit decoder and entry player.
 | 
	
		
			
				|  |  | -+   */
 | 
	
		
			
				|  |  | -+  virtual bool GetCodecStats(double &pts, int &droppedPics)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    droppedPics= -1;
 | 
	
		
			
				|  |  | -+    return false;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  /**
 | 
	
		
			
				|  |  | -+   * Codec can be informed by player with the following flags:
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   * DVP_FLAG_NO_POSTPROC : if speed is not normal the codec can switch off
 | 
	
		
			
				|  |  | -+   *                        postprocessing and de-interlacing
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   * DVP_FLAG_DRAIN : codecs may do postprocessing and de-interlacing.
 | 
	
		
			
				|  |  | -+   *                  If video buffers in RenderManager are about to run dry,
 | 
	
		
			
				|  |  | -+   *                  this is signaled to codec. Codec can wait for post-proc
 | 
	
		
			
				|  |  | -+   *                  to be finished instead of returning empty and getting another
 | 
	
		
			
				|  |  | -+   *                  packet.
 | 
	
		
			
				|  |  | -+   *
 | 
	
		
			
				|  |  | -+   */
 | 
	
		
			
				|  |  | -+  virtual void SetCodecControl(int flags) {}
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
 | 
	
		
			
				|  |  | -index 9b6a34d..81fe0cf 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.cpp
 | 
	
		
			
				|  |  | -@@ -164,6 +164,7 @@ CDVDVideoCodecFFmpeg::CDVDVideoCodecFFmpeg() : CDVDVideoCodec()
 | 
	
		
			
				|  |  | -   m_iLastKeyframe = 0;
 | 
	
		
			
				|  |  | -   m_dts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -   m_started = false;
 | 
	
		
			
				|  |  | -+  m_decoderPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - CDVDVideoCodecFFmpeg::~CDVDVideoCodecFFmpeg()
 | 
	
		
			
				|  |  | -@@ -355,6 +356,14 @@ void CDVDVideoCodecFFmpeg::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   if( m_pCodecContext )
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -+    if (bDrop && m_pHardware && m_pHardware->CanSkipDeint())
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      m_requestSkipDeint = true;
 | 
	
		
			
				|  |  | -+      bDrop = false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else
 | 
	
		
			
				|  |  | -+      m_requestSkipDeint = false;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -     // i don't know exactly how high this should be set
 | 
	
		
			
				|  |  | -     // couldn't find any good docs on it. think it varies
 | 
	
		
			
				|  |  | -     // from codec to codec on what it does
 | 
	
		
			
				|  |  | -@@ -556,6 +565,7 @@ int CDVDVideoCodecFFmpeg::Decode(uint8_t* pData, int iSize, double dts, double p
 | 
	
		
			
				|  |  | - void CDVDVideoCodecFFmpeg::Reset()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   m_started = false;
 | 
	
		
			
				|  |  | -+  m_decoderPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -   m_iLastKeyframe = m_pCodecContext->has_b_frames;
 | 
	
		
			
				|  |  | -   m_dllAvCodec.avcodec_flush_buffers(m_pCodecContext);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -665,6 +675,22 @@ bool CDVDVideoCodecFFmpeg::GetPictureCommon(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
 | 
	
		
			
				|  |  | -+    m_decoderPts = pDvdVideoPicture->pts;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    m_decoderPts = m_dts;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_requestSkipDeint)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->iFlags |= DVP_FLAG_DROPDEINT;
 | 
	
		
			
				|  |  | -+    m_skippedDeint = 1;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    m_skippedDeint = 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_requestSkipDeint = false;
 | 
	
		
			
				|  |  | -+  pDvdVideoPicture->iFlags |= m_codecControlFlags;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   if(!m_started)
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->iFlags |= DVP_FLAG_DROPPED;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -924,3 +950,18 @@ unsigned CDVDVideoCodecFFmpeg::GetAllowedReferences()
 | 
	
		
			
				|  |  | -   else
 | 
	
		
			
				|  |  | -     return 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+bool CDVDVideoCodecFFmpeg::GetCodecStats(double &pts, int &droppedPics)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  pts = m_decoderPts;
 | 
	
		
			
				|  |  | -+  if (m_skippedDeint)
 | 
	
		
			
				|  |  | -+    droppedPics = m_skippedDeint;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    droppedPics = -1;
 | 
	
		
			
				|  |  | -+  return true;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CDVDVideoCodecFFmpeg::SetCodecControl(int flags)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  m_codecControlFlags = flags;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
 | 
	
		
			
				|  |  | -index 2287031..827c9507 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecFFmpeg.h
 | 
	
		
			
				|  |  | -@@ -45,6 +45,7 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
 | 
	
		
			
				|  |  | -     virtual int  Check     (AVCodecContext* avctx) = 0;
 | 
	
		
			
				|  |  | -     virtual void Reset     () {}
 | 
	
		
			
				|  |  | -     virtual unsigned GetAllowedReferences() { return 0; }
 | 
	
		
			
				|  |  | -+    virtual bool CanSkipDeint() {return false; }
 | 
	
		
			
				|  |  | -     virtual const std::string Name() = 0;
 | 
	
		
			
				|  |  | -     virtual CCriticalSection* Section() { return NULL; }
 | 
	
		
			
				|  |  | -   };
 | 
	
		
			
				|  |  | -@@ -62,6 +63,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
 | 
	
		
			
				|  |  | -   virtual const char* GetName() { return m_name.c_str(); }; // m_name is never changed after open
 | 
	
		
			
				|  |  | -   virtual unsigned GetConvergeCount();
 | 
	
		
			
				|  |  | -   virtual unsigned GetAllowedReferences();
 | 
	
		
			
				|  |  | -+  virtual bool GetCodecStats(double &pts, int &droppedPics);
 | 
	
		
			
				|  |  | -+  virtual void SetCodecControl(int flags);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool               IsHardwareAllowed()                     { return !m_bSoftware; }
 | 
	
		
			
				|  |  | -   IHardwareDecoder * GetHardware()                           { return m_pHardware; };
 | 
	
		
			
				|  |  | -@@ -127,4 +130,8 @@ class CDVDVideoCodecFFmpeg : public CDVDVideoCodec
 | 
	
		
			
				|  |  | -   double m_dts;
 | 
	
		
			
				|  |  | -   bool   m_started;
 | 
	
		
			
				|  |  | -   std::vector<PixelFormat> m_formats;
 | 
	
		
			
				|  |  | -+  double m_decoderPts, m_decoderInterval;
 | 
	
		
			
				|  |  | -+  int    m_skippedDeint;
 | 
	
		
			
				|  |  | -+  bool   m_requestSkipDeint;
 | 
	
		
			
				|  |  | -+  int    m_codecControlFlags;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index fddb7f7..181ff74 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -38,6 +38,7 @@
 | 
	
		
			
				|  |  | - #include "DVDCodecs/DVDCodecs.h"
 | 
	
		
			
				|  |  | - #include "DVDCodecs/Overlay/DVDOverlayCodecCC.h"
 | 
	
		
			
				|  |  | - #include "DVDCodecs/Overlay/DVDOverlaySSA.h"
 | 
	
		
			
				|  |  | -+#include "guilib/GraphicContext.h"
 | 
	
		
			
				|  |  | - #include <sstream>
 | 
	
		
			
				|  |  | - #include <iomanip>
 | 
	
		
			
				|  |  | - #include <numeric>
 | 
	
		
			
				|  |  | -@@ -320,8 +321,10 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   int iDropped = 0; //frames dropped in a row
 | 
	
		
			
				|  |  | -   bool bRequestDrop = false;
 | 
	
		
			
				|  |  | -+  int iDropDirective;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_videoStats.Start();
 | 
	
		
			
				|  |  | -+  m_droppingStats.Reset();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   while (!m_bStop)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -@@ -436,6 +439,7 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | -       picture.iFlags &= ~DVP_FLAG_ALLOCATED;
 | 
	
		
			
				|  |  | -       m_packets.clear();
 | 
	
		
			
				|  |  | -       m_started = false;
 | 
	
		
			
				|  |  | -+      m_droppingStats.Reset();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     else if (pMsg->IsType(CDVDMsg::GENERAL_FLUSH)) // private message sent by (CDVDPlayerVideo::Flush())
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -@@ -448,6 +452,7 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | -       //we need to recalculate the framerate
 | 
	
		
			
				|  |  | -       //TODO: this needs to be set on a streamchange instead
 | 
	
		
			
				|  |  | -       ResetFrameRateCalc();
 | 
	
		
			
				|  |  | -+      m_droppingStats.Reset();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       m_stalled = true;
 | 
	
		
			
				|  |  | -       m_started = false;
 | 
	
		
			
				|  |  | -@@ -467,6 +472,7 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | -         m_iNrOfPicturesNotToSkip = 0;
 | 
	
		
			
				|  |  | -       if (m_pVideoCodec)
 | 
	
		
			
				|  |  | -         m_pVideoCodec->SetSpeed(m_speed);
 | 
	
		
			
				|  |  | -+      m_droppingStats.Reset();
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -     else if (pMsg->IsType(CDVDMsg::PLAYER_STARTED))
 | 
	
		
			
				|  |  | -     {
 | 
	
		
			
				|  |  | -@@ -515,6 +521,28 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | -         m_iNrOfPicturesNotToSkip = 1;
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+      bRequestDrop = false;
 | 
	
		
			
				|  |  | -+      iDropDirective = CalcDropRequirement(pts);
 | 
	
		
			
				|  |  | -+      if (iDropDirective & EOS_VERYLATE)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        if (m_bAllowDrop)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          m_pullupCorrection.Flush();
 | 
	
		
			
				|  |  | -+          bRequestDrop = true;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      int codecControl = 0;
 | 
	
		
			
				|  |  | -+      if (iDropDirective & EOS_BUFFER_LEVEL)
 | 
	
		
			
				|  |  | -+        codecControl |= DVP_FLAG_DRAIN;
 | 
	
		
			
				|  |  | -+      if (m_speed > DVD_PLAYSPEED_NORMAL)
 | 
	
		
			
				|  |  | -+        codecControl |= DVP_FLAG_NO_POSTPROC;
 | 
	
		
			
				|  |  | -+      m_pVideoCodec->SetCodecControl(codecControl);
 | 
	
		
			
				|  |  | -+      if (iDropDirective & EOS_DROPPED)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        m_iDroppedFrames++;
 | 
	
		
			
				|  |  | -+        iDropped++;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -       if (m_messageQueue.GetDataSize() == 0
 | 
	
		
			
				|  |  | -       ||  m_speed < 0)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -@@ -567,15 +595,7 @@ void CDVDPlayerVideo::Process()
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       m_videoStats.AddSampleBytes(pPacket->iSize);
 | 
	
		
			
				|  |  | --      // assume decoder dropped a picture if it didn't give us any
 | 
	
		
			
				|  |  | --      // picture from a demux packet, this should be reasonable
 | 
	
		
			
				|  |  | --      // for libavformat as a demuxer as it normally packetizes
 | 
	
		
			
				|  |  | --      // pictures when they come from demuxer
 | 
	
		
			
				|  |  | --      if(bRequestDrop && !bPacketDrop && (iDecoderState & VC_BUFFER) && !(iDecoderState & VC_PICTURE))
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        m_iDroppedFrames++;
 | 
	
		
			
				|  |  | --        iDropped++;
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -       // reset the request, the following while loop may break before
 | 
	
		
			
				|  |  | -       // setting the flag to a new value
 | 
	
		
			
				|  |  | -       bRequestDrop = false;
 | 
	
		
			
				|  |  | -@@ -1185,33 +1205,12 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
 | 
	
		
			
				|  |  | -   m_FlipTimeStamp += max(0.0, iSleepTime);
 | 
	
		
			
				|  |  | -   m_FlipTimeStamp += iFrameDuration;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  if (iSleepTime <= 0 && m_speed)
 | 
	
		
			
				|  |  | --    m_iLateFrames++;
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --    m_iLateFrames = 0;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  // ask decoder to drop frames next round, as we are very late
 | 
	
		
			
				|  |  | --  if(m_iLateFrames > 10)
 | 
	
		
			
				|  |  | -+  if ((pPicture->iFlags & DVP_FLAG_DROPPED))
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    if (!(pPicture->iFlags & DVP_FLAG_NOSKIP))
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      //if we're calculating the framerate,
 | 
	
		
			
				|  |  | --      //don't drop frames until we've calculated a stable framerate
 | 
	
		
			
				|  |  | --      if (m_bAllowDrop || m_speed != DVD_PLAYSPEED_NORMAL)
 | 
	
		
			
				|  |  | --      {
 | 
	
		
			
				|  |  | --        result |= EOS_VERYLATE;
 | 
	
		
			
				|  |  | --        m_pullupCorrection.Flush(); //dropped frames mess up the pattern, so just flush it
 | 
	
		
			
				|  |  | --      }
 | 
	
		
			
				|  |  | --      m_iDroppedRequest++;
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --  else
 | 
	
		
			
				|  |  | --  {
 | 
	
		
			
				|  |  | --    m_iDroppedRequest = 0;
 | 
	
		
			
				|  |  | --  }
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --  if( (pPicture->iFlags & DVP_FLAG_DROPPED) )
 | 
	
		
			
				|  |  | -+    m_droppingStats.AddOutputDropGain(pts, 1/m_fFrameRate);
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG,"%s - dropped in output", __FUNCTION__);
 | 
	
		
			
				|  |  | -     return result | EOS_DROPPED;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // set fieldsync if picture is interlaced
 | 
	
		
			
				|  |  | -   EFIELDSYNC mDisplayField = FS_NONE;
 | 
	
		
			
				|  |  | -@@ -1244,7 +1243,7 @@ int CDVDPlayerVideo::OutputPicture(const DVDVideoPicture* src, double pts)
 | 
	
		
			
				|  |  | -   if (index < 0)
 | 
	
		
			
				|  |  | -     return EOS_DROPPED;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, -1, mDisplayField);
 | 
	
		
			
				|  |  | -+  g_renderManager.FlipPage(CThread::m_bStop, (iCurrentClock + iSleepTime) / DVD_TIME_BASE, pts, -1, mDisplayField);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   return result;
 | 
	
		
			
				|  |  | - #else
 | 
	
		
			
				|  |  | -@@ -1544,3 +1543,131 @@ void CDVDPlayerVideo::CalcFrameRate()
 | 
	
		
			
				|  |  | -     m_iFrameRateCount = 0;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+int CDVDPlayerVideo::CalcDropRequirement(double pts)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  int result = 0;
 | 
	
		
			
				|  |  | -+  double iSleepTime;
 | 
	
		
			
				|  |  | -+  double iDecoderPts, iRenderPts;
 | 
	
		
			
				|  |  | -+  double iInterval;
 | 
	
		
			
				|  |  | -+  double iGain;
 | 
	
		
			
				|  |  | -+  double iLateness;
 | 
	
		
			
				|  |  | -+  bool   bNewFrame;
 | 
	
		
			
				|  |  | -+  int    iDroppedPics = -1;
 | 
	
		
			
				|  |  | -+  int    iBufferLevel;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // get decoder stats
 | 
	
		
			
				|  |  | -+  if (!m_pVideoCodec->GetCodecStats(iDecoderPts, iDroppedPics))
 | 
	
		
			
				|  |  | -+    iDecoderPts = pts;
 | 
	
		
			
				|  |  | -+  if (iDecoderPts == DVD_NOPTS_VALUE)
 | 
	
		
			
				|  |  | -+    iDecoderPts = pts;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // get render stats
 | 
	
		
			
				|  |  | -+  g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (iBufferLevel < 0)
 | 
	
		
			
				|  |  | -+    result |= EOS_BUFFER_LEVEL;
 | 
	
		
			
				|  |  | -+  else if (iBufferLevel < 2)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    result |= EOS_BUFFER_LEVEL;
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - hurry: %d", iBufferLevel);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  bNewFrame = iDecoderPts != m_droppingStats.m_lastDecoderPts;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  iInterval = 1/m_fFrameRate*(double)DVD_TIME_BASE;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  m_FlipTimeStamp = m_pClock->GetAbsoluteClock() + max(0.0, iSleepTime) + iInterval;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_stalled)
 | 
	
		
			
				|  |  | -+    m_iCurrentPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    m_iCurrentPts = iRenderPts - max(0.0, iSleepTime);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (m_droppingStats.m_lastDecoderPts > 0
 | 
	
		
			
				|  |  | -+      && bNewFrame
 | 
	
		
			
				|  |  | -+      && m_bAllowDrop)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    iGain = (iDecoderPts - m_droppingStats.m_lastDecoderPts - iInterval)/(double)DVD_TIME_BASE;
 | 
	
		
			
				|  |  | -+    if (iDroppedPics > 0)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CDroppingStats::CGain gain;
 | 
	
		
			
				|  |  | -+      gain.gain = iDroppedPics * 1/m_fFrameRate;
 | 
	
		
			
				|  |  | -+      gain.pts = iDecoderPts;
 | 
	
		
			
				|  |  | -+      m_droppingStats.m_gain.push_back(gain);
 | 
	
		
			
				|  |  | -+      m_droppingStats.m_totalGain += gain.gain;
 | 
	
		
			
				|  |  | -+      result |= EOS_DROPPED;
 | 
	
		
			
				|  |  | -+      m_droppingStats.m_dropRequests = 0;
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped pictures, Sleeptime: %f, Bufferlevel: %d, Gain: %f", iSleepTime, iBufferLevel, iGain);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+    else if (iDroppedPics < 0 && iGain > 1/m_fFrameRate)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CDroppingStats::CGain gain;
 | 
	
		
			
				|  |  | -+      gain.gain = iGain;
 | 
	
		
			
				|  |  | -+      gain.pts = iDecoderPts;
 | 
	
		
			
				|  |  | -+      m_droppingStats.m_gain.push_back(gain);
 | 
	
		
			
				|  |  | -+      m_droppingStats.m_totalGain += iGain;
 | 
	
		
			
				|  |  | -+      result |= EOS_DROPPED;
 | 
	
		
			
				|  |  | -+      m_droppingStats.m_dropRequests = 0;
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGDEBUG,"CDVDPlayerVideo::CalcDropRequirement - dropped in decoder, Sleeptime: %f, Bufferlevel: %d, Gain: %f", iSleepTime, iBufferLevel, iGain);
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  m_droppingStats.m_lastDecoderPts = iDecoderPts;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // subtract gains
 | 
	
		
			
				|  |  | -+  while (!m_droppingStats.m_gain.empty() &&
 | 
	
		
			
				|  |  | -+         iRenderPts >= m_droppingStats.m_gain.front().pts)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_droppingStats.m_totalGain -= m_droppingStats.m_gain.front().gain;
 | 
	
		
			
				|  |  | -+    m_droppingStats.m_gain.pop_front();
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // calculate lateness
 | 
	
		
			
				|  |  | -+  iLateness = iSleepTime + m_droppingStats.m_totalGain;
 | 
	
		
			
				|  |  | -+  if (iLateness < 0 && m_speed)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    if (bNewFrame)
 | 
	
		
			
				|  |  | -+      m_droppingStats.m_lateFrames++;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    // if lateness is smaller than frametime, we observe this state
 | 
	
		
			
				|  |  | -+    // for 10 cycles
 | 
	
		
			
				|  |  | -+    if (m_droppingStats.m_lateFrames > 10 || iLateness < -2/m_fFrameRate)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      // is frame allowed to skip
 | 
	
		
			
				|  |  | -+      if (m_iNrOfPicturesNotToSkip <= 0)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        if (bNewFrame || m_droppingStats.m_dropRequests < 5)
 | 
	
		
			
				|  |  | -+        {
 | 
	
		
			
				|  |  | -+          result |= EOS_VERYLATE;
 | 
	
		
			
				|  |  | -+        }
 | 
	
		
			
				|  |  | -+        m_droppingStats.m_dropRequests++;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    m_droppingStats.m_dropRequests = 0;
 | 
	
		
			
				|  |  | -+    m_droppingStats.m_lateFrames = 0;
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  m_droppingStats.m_lastRenderPts = iRenderPts;
 | 
	
		
			
				|  |  | -+  return result;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CDroppingStats::Reset()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  m_gain.clear();
 | 
	
		
			
				|  |  | -+  m_totalGain = 0;
 | 
	
		
			
				|  |  | -+  m_lastDecoderPts = 0;
 | 
	
		
			
				|  |  | -+  m_lastRenderPts = 0;
 | 
	
		
			
				|  |  | -+  m_lateFrames = 0;
 | 
	
		
			
				|  |  | -+  m_dropRequests = 0;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+void CDroppingStats::AddOutputDropGain(double pts, double frametime)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  CDroppingStats::CGain gain;
 | 
	
		
			
				|  |  | -+  gain.gain = frametime;
 | 
	
		
			
				|  |  | -+  gain.pts = pts;
 | 
	
		
			
				|  |  | -+  m_gain.push_back(gain);
 | 
	
		
			
				|  |  | -+  m_totalGain += frametime;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
 | 
	
		
			
				|  |  | -index f8ad541..186e271 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
 | 
	
		
			
				|  |  | -@@ -36,6 +36,25 @@ class CDVDOverlayCodecCC;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define VIDEO_PICTURE_QUEUE_SIZE 1
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+class CDroppingStats
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+public:
 | 
	
		
			
				|  |  | -+  void Reset();
 | 
	
		
			
				|  |  | -+  void AddOutputDropGain(double pts, double frametime);
 | 
	
		
			
				|  |  | -+  struct CGain
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    double gain;
 | 
	
		
			
				|  |  | -+    double pts;
 | 
	
		
			
				|  |  | -+  };
 | 
	
		
			
				|  |  | -+  std::deque<CGain> m_gain;
 | 
	
		
			
				|  |  | -+  double m_totalGain;
 | 
	
		
			
				|  |  | -+  double m_lastDecoderPts;
 | 
	
		
			
				|  |  | -+  double m_lastRenderPts;
 | 
	
		
			
				|  |  | -+  unsigned int m_lateFrames;
 | 
	
		
			
				|  |  | -+  unsigned int m_dropRequests;
 | 
	
		
			
				|  |  | -+};
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - class CDVDPlayerVideo : public CThread
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | - public:
 | 
	
		
			
				|  |  | -@@ -104,6 +123,7 @@ class CDVDPlayerVideo : public CThread
 | 
	
		
			
				|  |  | - #define EOS_ABORT 1
 | 
	
		
			
				|  |  | - #define EOS_DROPPED 2
 | 
	
		
			
				|  |  | - #define EOS_VERYLATE 4
 | 
	
		
			
				|  |  | -+#define EOS_BUFFER_LEVEL 8
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   void AutoCrop(DVDVideoPicture* pPicture);
 | 
	
		
			
				|  |  | -   void AutoCrop(DVDVideoPicture *pPicture, RECT &crop);
 | 
	
		
			
				|  |  | -@@ -129,6 +149,7 @@ class CDVDPlayerVideo : public CThread
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   void   ResetFrameRateCalc();
 | 
	
		
			
				|  |  | -   void   CalcFrameRate();
 | 
	
		
			
				|  |  | -+  int    CalcDropRequirement(double pts);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   double m_fFrameRate;       //framerate of the video currently playing
 | 
	
		
			
				|  |  | -   bool   m_bCalcFrameRate;  //if we should calculate the framerate from the timestamps
 | 
	
		
			
				|  |  | -@@ -182,5 +203,7 @@ class CDVDPlayerVideo : public CThread
 | 
	
		
			
				|  |  | -   CPullupCorrection m_pullupCorrection;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   std::list<DVDMessageListItem> m_packets;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  CDroppingStats m_droppingStats;
 | 
	
		
			
				|  |  | - };
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 16d2c2ee305eb2cd3ec42fd0aad474dbf356d75d Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: xbmc <fernetmenta@online.de>
 | 
	
		
			
				|  |  | -Date: Sun, 2 Sep 2012 16:05:21 +0200
 | 
	
		
			
				|  |  | -Subject: [PATCH 85/94] video player: present correct pts to user for a/v sync
 | 
	
		
			
				|  |  | - (after buffering in renderer)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDPlayerVideo.cpp | 16 ++++++++++++++++
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDPlayerVideo.h   |  2 +-
 | 
	
		
			
				|  |  | - 2 files changed, 17 insertions(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index 181ff74..01757cc 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -1463,6 +1463,22 @@ void CDVDPlayerVideo::ResetFrameRateCalc()
 | 
	
		
			
				|  |  | -                         g_advancedSettings.m_videoFpsDetect == 0;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+double CDVDPlayerVideo::GetCurrentPts()
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  double iSleepTime, iRenderPts;
 | 
	
		
			
				|  |  | -+  int iBufferLevel;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // get render stats
 | 
	
		
			
				|  |  | -+  g_renderManager.GetStats(iSleepTime, iRenderPts, iBufferLevel);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if( m_stalled )
 | 
	
		
			
				|  |  | -+    iRenderPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    iRenderPts = iRenderPts - max(0.0, iSleepTime);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  return iRenderPts;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #define MAXFRAMERATEDIFF   0.01
 | 
	
		
			
				|  |  | - #define MAXFRAMESERR    1000
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDPlayerVideo.h b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
 | 
	
		
			
				|  |  | -index 186e271..59c7f09 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDPlayerVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDPlayerVideo.h
 | 
	
		
			
				|  |  | -@@ -100,7 +100,7 @@ class CDVDPlayerVideo : public CThread
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool InitializedOutputDevice();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --  double GetCurrentPts()                           { return m_iCurrentPts; }
 | 
	
		
			
				|  |  | -+  double GetCurrentPts();
 | 
	
		
			
				|  |  | -   int    GetPullupCorrection()                     { return m_pullupCorrection.GetPatternLength(); }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   double GetOutputDelay(); /* returns the expected delay, from that a packet is put in queue */
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From afa38b57afee02720263e2db79d20e1411461433 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Mon, 12 May 2014 23:06:43 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 86/94] [omxcodec] Updates to work better with dropping and
 | 
	
		
			
				|  |  | - lateness detection
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecOpenMax.cpp       |  5 ++
 | 
	
		
			
				|  |  | - .../DVDCodecs/Video/DVDVideoCodecOpenMax.h         |  1 +
 | 
	
		
			
				|  |  | - .../dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp     | 95 ++++++++++++++++------
 | 
	
		
			
				|  |  | - .../cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h |  9 +-
 | 
	
		
			
				|  |  | - 4 files changed, 84 insertions(+), 26 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -index ef10555..8323497 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.cpp
 | 
	
		
			
				|  |  | -@@ -91,4 +91,9 @@ bool CDVDVideoCodecOpenMax::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -   return m_omx_decoder->ClearPicture(pDvdVideoPicture);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+bool CDVDVideoCodecOpenMax::GetCodecStats(double &pts, int &droppedPics)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  return m_omx_decoder->GetCodecStats(pts, droppedPics);
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -index b7c0c1b..4f243df 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/DVDVideoCodecOpenMax.h
 | 
	
		
			
				|  |  | -@@ -41,6 +41,7 @@ class CDVDVideoCodecOpenMax : public CDVDVideoCodec
 | 
	
		
			
				|  |  | -   virtual unsigned GetAllowedReferences();
 | 
	
		
			
				|  |  | -   virtual void SetDropState(bool bDrop);
 | 
	
		
			
				|  |  | -   virtual const char* GetName(void);
 | 
	
		
			
				|  |  | -+  virtual bool GetCodecStats(double &pts, int &droppedPics);
 | 
	
		
			
				|  |  | -   
 | 
	
		
			
				|  |  | - protected:
 | 
	
		
			
				|  |  | -   OpenMaxVideoPtr m_omx_decoder;
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index 71d19af..93cf521 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -37,6 +37,7 @@
 | 
	
		
			
				|  |  | - #include "ApplicationMessenger.h"
 | 
	
		
			
				|  |  | - #include "Application.h"
 | 
	
		
			
				|  |  | - #include "threads/Atomics.h"
 | 
	
		
			
				|  |  | -+#include "guilib/GUIWindowManager.h"
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #include <IL/OMX_Core.h>
 | 
	
		
			
				|  |  | - #include <IL/OMX_Component.h>
 | 
	
		
			
				|  |  | -@@ -57,6 +58,7 @@
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #define OMX_BUFFERFLAG_PTS_INVALID (1<<28)
 | 
	
		
			
				|  |  | - #define OMX_BUFFERFLAG_DROPPED     (1<<29)
 | 
	
		
			
				|  |  | -+#define OMX_BUFFERFLAG_FIRST_FIELD (1<<30)
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - COpenMaxVideoBuffer::COpenMaxVideoBuffer(COpenMaxVideo *omv)
 | 
	
		
			
				|  |  | -     : m_omv(omv), m_refs(0)
 | 
	
		
			
				|  |  | -@@ -139,8 +141,11 @@ COpenMaxVideo::COpenMaxVideo()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   m_deinterlace = false;
 | 
	
		
			
				|  |  | -   m_deinterlace_request = VS_DEINTERLACEMODE_OFF;
 | 
	
		
			
				|  |  | --  m_deinterlace_second_field = false;
 | 
	
		
			
				|  |  | -   m_startframe = false;
 | 
	
		
			
				|  |  | -+  m_decoderPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -+  m_droppedPics = 0;
 | 
	
		
			
				|  |  | -+  m_decode_frame_number = 1;
 | 
	
		
			
				|  |  | -+  m_skipDeinterlaceFields = false;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - COpenMaxVideo::~COpenMaxVideo()
 | 
	
		
			
				|  |  | -@@ -369,7 +374,10 @@ void COpenMaxVideo::Dispose()
 | 
	
		
			
				|  |  | -   m_finished = true;
 | 
	
		
			
				|  |  | -   pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -   if (done)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    assert(m_dts_queue.empty());
 | 
	
		
			
				|  |  | -     m_myself.reset();
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void COpenMaxVideo::SetDropState(bool bDrop)
 | 
	
		
			
				|  |  | -@@ -730,6 +738,7 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | -       omx_buffer->nFilledLen = (demuxer_bytes > omx_buffer->nAllocLen) ? omx_buffer->nAllocLen : demuxer_bytes;
 | 
	
		
			
				|  |  | -       omx_buffer->nTimeStamp = ToOMXTime((uint64_t)(pts == DVD_NOPTS_VALUE) ? 0 : pts);
 | 
	
		
			
				|  |  | -       omx_buffer->pAppPrivate = omx_buffer;
 | 
	
		
			
				|  |  | -+      omx_buffer->pMarkData = (OMX_PTR)m_decode_frame_number;
 | 
	
		
			
				|  |  | -       memcpy(omx_buffer->pBuffer, demuxer_content, omx_buffer->nFilledLen);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       demuxer_bytes -= omx_buffer->nFilledLen;
 | 
	
		
			
				|  |  | -@@ -742,12 +751,18 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | -         omx_buffer->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
 | 
	
		
			
				|  |  | -       if (pts == DVD_NOPTS_VALUE) // hijack an omx flag to indicate there wasn't a real timestamp - it will be returned with the picture (but otherwise ignored)
 | 
	
		
			
				|  |  | -         omx_buffer->nFlags |= OMX_BUFFERFLAG_PTS_INVALID;
 | 
	
		
			
				|  |  | --      if (m_drop_state) // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
 | 
	
		
			
				|  |  | -+      if (m_drop_state)
 | 
	
		
			
				|  |  | -+      {
 | 
	
		
			
				|  |  | -+        // hijack an omx flag to signal this frame to be dropped - it will be returned with the picture (but otherwise ignored)
 | 
	
		
			
				|  |  | -         omx_buffer->nFlags |= OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED;
 | 
	
		
			
				|  |  | -+        m_droppedPics += m_deinterlace ? 2:1;
 | 
	
		
			
				|  |  | -+      }
 | 
	
		
			
				|  |  | -+      // always set this flag on input. It won't be set on second field of interlaced video.
 | 
	
		
			
				|  |  | -+      omx_buffer->nFlags |= OMX_BUFFERFLAG_FIRST_FIELD;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x",
 | 
	
		
			
				|  |  | --        CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags);
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGDEBUG, "%s::%s - %-6d dts:%.3f pts:%.3f flags:%x frame:%d",
 | 
	
		
			
				|  |  | -+        CLASSNAME, __func__, omx_buffer->nFilledLen, dts == DVD_NOPTS_VALUE ? 0.0 : dts*1e-6, pts == DVD_NOPTS_VALUE ? 0.0 : pts*1e-6, omx_buffer->nFlags, (int)omx_buffer->pMarkData);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       omx_err = m_omx_decoder.EmptyThisBuffer(omx_buffer);
 | 
	
		
			
				|  |  | -@@ -758,13 +773,16 @@ int COpenMaxVideo::Decode(uint8_t* pData, int iSize, double dts, double pts)
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -       if (demuxer_bytes == 0)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -+        m_decode_frame_number++;
 | 
	
		
			
				|  |  | -         m_startframe = true;
 | 
	
		
			
				|  |  | - #ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -         if (!m_drop_state)
 | 
	
		
			
				|  |  | -         {
 | 
	
		
			
				|  |  | -           // only push if we are successful with feeding OMX_EmptyThisBuffer
 | 
	
		
			
				|  |  | -+          pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -           m_dts_queue.push(dts);
 | 
	
		
			
				|  |  | -           assert(m_dts_queue.size() < 32);
 | 
	
		
			
				|  |  | -+          pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -         }
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -         if (buffer_to_free)
 | 
	
		
			
				|  |  | -@@ -840,13 +858,18 @@ void COpenMaxVideo::Reset(void)
 | 
	
		
			
				|  |  | -   SetDropState(true);
 | 
	
		
			
				|  |  | -   SetDropState(false);
 | 
	
		
			
				|  |  | - #ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -+  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -   while (!m_dts_queue.empty())
 | 
	
		
			
				|  |  | -     m_dts_queue.pop();
 | 
	
		
			
				|  |  | -+  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   while (!m_demux_queue.empty())
 | 
	
		
			
				|  |  | -     m_demux_queue.pop();
 | 
	
		
			
				|  |  | -   m_startframe = false;
 | 
	
		
			
				|  |  | -+  m_decoderPts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | -+  m_droppedPics = 0;
 | 
	
		
			
				|  |  | -+  m_decode_frame_number = 1;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -928,26 +951,17 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --#ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | --    if (!m_deinterlace_second_field)
 | 
	
		
			
				|  |  | --    {
 | 
	
		
			
				|  |  | --      assert(!m_dts_queue.empty());
 | 
	
		
			
				|  |  | --      pDvdVideoPicture->dts = m_dts_queue.front();
 | 
	
		
			
				|  |  | --      m_dts_queue.pop();
 | 
	
		
			
				|  |  | --    }
 | 
	
		
			
				|  |  | --    if (m_deinterlace)
 | 
	
		
			
				|  |  | --      m_deinterlace_second_field = !m_deinterlace_second_field;
 | 
	
		
			
				|  |  | --#endif
 | 
	
		
			
				|  |  | -     // nTimeStamp is in microseconds
 | 
	
		
			
				|  |  | -+    pDvdVideoPicture->dts = buffer->dts;
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->pts = FromOMXTime(buffer->omx_buffer->nTimeStamp);
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->openMaxBuffer->Acquire();
 | 
	
		
			
				|  |  | -     pDvdVideoPicture->iFlags  = DVP_FLAG_ALLOCATED;
 | 
	
		
			
				|  |  | -     if (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_PTS_INVALID)
 | 
	
		
			
				|  |  | -       pDvdVideoPicture->pts = DVD_NOPTS_VALUE;
 | 
	
		
			
				|  |  | - #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --    CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGINFO, "%s::%s dts:%.3f pts:%.3f flags:%x:%x frame:%d openMaxBuffer:%p omx_buffer:%p egl_image:%p texture_id:%x", CLASSNAME, __func__,
 | 
	
		
			
				|  |  | -         pDvdVideoPicture->dts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->dts*1e-6, pDvdVideoPicture->pts == DVD_NOPTS_VALUE ? 0.0 : pDvdVideoPicture->pts*1e-6,
 | 
	
		
			
				|  |  | --        pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
 | 
	
		
			
				|  |  | -+        pDvdVideoPicture->iFlags, buffer->omx_buffer->nFlags, (int)buffer->omx_buffer->pMarkData, pDvdVideoPicture->openMaxBuffer, pDvdVideoPicture->openMaxBuffer->omx_buffer, pDvdVideoPicture->openMaxBuffer->egl_image, pDvdVideoPicture->openMaxBuffer->texture_id);
 | 
	
		
			
				|  |  | - #endif
 | 
	
		
			
				|  |  | -     assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -@@ -956,6 +970,12 @@ bool COpenMaxVideo::GetPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -     CLog::Log(LOGERROR, "%s::%s - called but m_omx_output_ready is empty", CLASSNAME, __func__);
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  if (pDvdVideoPicture->pts != DVD_NOPTS_VALUE)
 | 
	
		
			
				|  |  | -+    m_decoderPts = pDvdVideoPicture->pts;
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+    m_decoderPts = pDvdVideoPicture->dts; // xxx is DVD_NOPTS_VALUE better?
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -@@ -970,25 +990,54 @@ bool COpenMaxVideo::ClearPicture(DVDVideoPicture* pDvdVideoPicture)
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+bool COpenMaxVideo::GetCodecStats(double &pts, int &droppedPics)
 | 
	
		
			
				|  |  | -+{
 | 
	
		
			
				|  |  | -+  pts = m_decoderPts;
 | 
	
		
			
				|  |  | -+  droppedPics = m_droppedPics;
 | 
	
		
			
				|  |  | -+  m_droppedPics = 0;
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - pts:%.0f droppedPics:%d", CLASSNAME, __func__, pts, droppedPics);
 | 
	
		
			
				|  |  | -+    return true;
 | 
	
		
			
				|  |  | -+}
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // DecoderFillBufferDone -- OpenMax output buffer has been filled
 | 
	
		
			
				|  |  | - OMX_ERRORTYPE COpenMaxVideo::DecoderFillBufferDone(
 | 
	
		
			
				|  |  | -   OMX_HANDLETYPE hComponent,
 | 
	
		
			
				|  |  | -   OMX_BUFFERHEADERTYPE* pBuffer)
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | -   COpenMaxVideoBuffer *buffer = (COpenMaxVideoBuffer*)pBuffer->pAppPrivate;
 | 
	
		
			
				|  |  | -+  bool skipDeinterlaceFields = m_skipDeinterlaceFields || g_windowManager.HasDialogOnScreen();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   #if defined(OMX_DEBUG_VERBOSE)
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x",
 | 
	
		
			
				|  |  | --    CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags);
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGDEBUG, "%s::%s - %p (%p,%p) buffer_size(%u), pts:%.3f flags:%x frame:%d win:%x",
 | 
	
		
			
				|  |  | -+    CLASSNAME, __func__, buffer, pBuffer, buffer->omx_buffer, pBuffer->nFilledLen, (double)FromOMXTime(buffer->omx_buffer->nTimeStamp)*1e-6, buffer->omx_buffer->nFlags, (int)buffer->omx_buffer->pMarkData, skipDeinterlaceFields);
 | 
	
		
			
				|  |  | -   #endif
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   assert(!(buffer->omx_buffer->nFlags & (OMX_BUFFERFLAG_DECODEONLY | OMX_BUFFERFLAG_DROPPED)));
 | 
	
		
			
				|  |  | --  // queue output omx buffer to ready list.
 | 
	
		
			
				|  |  | --  pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | --  buffer->m_aspect_ratio = m_aspect_ratio;
 | 
	
		
			
				|  |  | --  m_omx_output_ready.push(buffer);
 | 
	
		
			
				|  |  | --  pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+  // flags have OMX_BUFFERFLAG_FIRST_FIELD set if this is a direct result of a submitted frame,
 | 
	
		
			
				|  |  | -+  // clear for second field of deinterlaced frame. They are zero when frame is returned due to a flush.
 | 
	
		
			
				|  |  | -+#ifdef DTS_QUEUE
 | 
	
		
			
				|  |  | -+  if ((!m_deinterlace || (buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_FIRST_FIELD)) && buffer->omx_buffer->nFlags)
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+    assert(!m_dts_queue.empty());
 | 
	
		
			
				|  |  | -+    buffer->dts = m_dts_queue.front();
 | 
	
		
			
				|  |  | -+    m_dts_queue.pop();
 | 
	
		
			
				|  |  | -+    pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -+  if (m_drop_state || (m_deinterlace && skipDeinterlaceFields && !(buffer->omx_buffer->nFlags & OMX_BUFFERFLAG_FIRST_FIELD)))
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    ReturnOpenMaxBuffer(buffer);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+  else
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    buffer->m_aspect_ratio = m_aspect_ratio;
 | 
	
		
			
				|  |  | -+    pthread_mutex_lock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+    m_omx_output_ready.push(buffer);
 | 
	
		
			
				|  |  | -+    pthread_mutex_unlock(&m_omx_output_mutex);
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -   return OMX_ErrorNone;
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -index f234f6d..adf53b5 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.h
 | 
	
		
			
				|  |  | -@@ -57,6 +57,7 @@ class COpenMaxVideoBuffer
 | 
	
		
			
				|  |  | -   int height;
 | 
	
		
			
				|  |  | -   float m_aspect_ratio;
 | 
	
		
			
				|  |  | -   int index;
 | 
	
		
			
				|  |  | -+  double dts;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // used for egl based rendering if active
 | 
	
		
			
				|  |  | -   EGLImageKHR egl_image;
 | 
	
		
			
				|  |  | -@@ -87,6 +88,7 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | -   virtual unsigned GetAllowedReferences() { return 2; }
 | 
	
		
			
				|  |  | -   virtual void SetDropState(bool bDrop);
 | 
	
		
			
				|  |  | -   virtual const char* GetName(void) { return (const char*)m_pFormatName; }
 | 
	
		
			
				|  |  | -+  virtual bool GetCodecStats(double &pts, int &droppedPics);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // OpenMax decoder callback routines.
 | 
	
		
			
				|  |  | -   OMX_ERRORTYPE DecoderFillBufferDone(OMX_HANDLETYPE hComponent, OMX_BUFFERHEADERTYPE* pBuffer);
 | 
	
		
			
				|  |  | -@@ -142,10 +144,11 @@ class COpenMaxVideo
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   bool              m_deinterlace;
 | 
	
		
			
				|  |  | -   EDEINTERLACEMODE  m_deinterlace_request;
 | 
	
		
			
				|  |  | --  bool              m_deinterlace_second_field;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -   bool              m_startframe;
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -+  unsigned int      m_decode_frame_number;
 | 
	
		
			
				|  |  | -+  double            m_decoderPts;
 | 
	
		
			
				|  |  | -+  unsigned int      m_droppedPics;
 | 
	
		
			
				|  |  | -+  bool              m_skipDeinterlaceFields;
 | 
	
		
			
				|  |  | -   bool PortSettingsChanged();
 | 
	
		
			
				|  |  | -   bool SendDecoderConfig(uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | -   bool NaluFormatStartCodes(enum AVCodecID codec, uint8_t *extradata, int extrasize);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 4dd2fcf0f479b6b18dac9a496ddf1788b82388f2 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sun, 11 May 2014 16:13:45 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 87/94] [rbp] Add config.txt settings to log file
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/linux/RBP.cpp | 8 +++++++-
 | 
	
		
			
				|  |  | - 1 file changed, 7 insertions(+), 1 deletion(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
 | 
	
		
			
				|  |  | -index 49dcbb8..9a5e9cb 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/RBP.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/RBP.cpp
 | 
	
		
			
				|  |  | -@@ -79,11 +79,17 @@ bool CRBP::Initialize()
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CRBP::LogFirmwareVerison()
 | 
	
		
			
				|  |  | - {
 | 
	
		
			
				|  |  | --  char  response[160];
 | 
	
		
			
				|  |  | -+  char  response[1024];
 | 
	
		
			
				|  |  | -   m_DllBcmHost->vc_gencmd(response, sizeof response, "version");
 | 
	
		
			
				|  |  | -   response[sizeof(response) - 1] = '\0';
 | 
	
		
			
				|  |  | -   CLog::Log(LOGNOTICE, "Raspberry PI firmware version: %s", response);
 | 
	
		
			
				|  |  | -   CLog::Log(LOGNOTICE, "ARM mem: %dMB GPU mem: %dMB MPG2:%d WVC1:%d", m_arm_mem, m_gpu_mem, m_codec_mpg2_enabled, m_codec_wvc1_enabled);
 | 
	
		
			
				|  |  | -+  m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config int");
 | 
	
		
			
				|  |  | -+  response[sizeof(response) - 1] = '\0';
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGNOTICE, "Config:\n%s", response);
 | 
	
		
			
				|  |  | -+  m_DllBcmHost->vc_gencmd(response, sizeof response, "get_config str");
 | 
	
		
			
				|  |  | -+  response[sizeof(response) - 1] = '\0';
 | 
	
		
			
				|  |  | -+  CLog::Log(LOGNOTICE, "Config:\n%s", response);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | - void CRBP::GetDisplaySize(int &width, int &height)
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From eb2cba833f1399befcbd60901f3d97a08e3a2781 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: Alex Deryskyba <alex@codesnake.com>
 | 
	
		
			
				|  |  | -Date: Thu, 8 May 2014 18:54:54 +0300
 | 
	
		
			
				|  |  | -Subject: [PATCH 88/94] Reset display region when video stream properties
 | 
	
		
			
				|  |  | - change
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Currently when video stream properties change, e.g. when user switches to next or previous Live TV channel, and has the same frame width and height, the COMXVideo::SetVideoRect() method is not called, causing the video to play back with default source and destination rectangles, not respecting the user-defined zoom settings.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This commit fixes the issue.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXPlayerVideo.cpp | 3 +++
 | 
	
		
			
				|  |  | - 1 file changed, 3 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -index 61b884e..eaa1e34 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXPlayerVideo.cpp
 | 
	
		
			
				|  |  | -@@ -781,6 +781,9 @@ void OMXPlayerVideo::ResolutionUpdateCallBack(uint32_t width, uint32_t height, f
 | 
	
		
			
				|  |  | -     return;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  m_src_rect.SetRect(0, 0, 0, 0);
 | 
	
		
			
				|  |  | -+  m_dst_rect.SetRect(0, 0, 0, 0);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   g_renderManager.RegisterRenderUpdateCallBack((const void*)this, RenderUpdateCallBack);
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 7c369ba5ec4e700f5c06e1caa20095bc26e61195 Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 28 May 2014 23:44:11 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 89/94] [omxplayer] Fix for mapping of multichannel PCM audio
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXAudio.cpp | 11 ++++++++---
 | 
	
		
			
				|  |  | - 1 file changed, 8 insertions(+), 3 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXAudio.cpp b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -index d9beb68..75eff26 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXAudio.cpp
 | 
	
		
			
				|  |  | -@@ -606,13 +606,18 @@ bool COMXAudio::Initialize(AEAudioFormat format, OMXClock *clock, CDVDStreamInfo
 | 
	
		
			
				|  |  | -     if (m_InputChannels <= 2)
 | 
	
		
			
				|  |  | -       stdLayout = AE_CH_LAYOUT_2_0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --    uint64_t m_dst_chan_layout = GetAVChannelLayout(stdLayout);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    CAEChannelInfo resolvedMap = channelMap;
 | 
	
		
			
				|  |  | -+    resolvedMap.ResolveChannels(stdLayout);
 | 
	
		
			
				|  |  | -+    uint64_t m_dst_chan_layout = GetAVChannelLayout(resolvedMap);
 | 
	
		
			
				|  |  | -     uint64_t m_src_chan_layout = GetAVChannelLayout(channelMap);
 | 
	
		
			
				|  |  | --    m_OutputChannels = stdLayout.Count();
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    m_InputChannels = channelMap.Count();
 | 
	
		
			
				|  |  | -+    m_OutputChannels = resolvedMap.Count();
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     int m_dst_channels = m_OutputChannels;
 | 
	
		
			
				|  |  | -     int m_src_channels = m_InputChannels;
 | 
	
		
			
				|  |  | --    SetAudioProps(m_Passthrough, GetChannelMap(stdLayout, m_Passthrough));
 | 
	
		
			
				|  |  | -+    SetAudioProps(m_Passthrough, GetChannelMap(resolvedMap, m_Passthrough));
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -     CLog::Log(LOGINFO, "%s::%s remap:%p chan:%d->%d norm:%d upmix:%d %llx:%llx", CLASSNAME, __func__, remapLayout, m_src_channels, m_dst_channels, normalize, upmix, m_src_chan_layout, m_dst_chan_layout);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 458ec80741e4aa1ae95fe616f5953e1268a4802e Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Fri, 30 May 2014 14:15:10 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 90/94] [pi] Fix for logged resolutions
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp | 15 +++++----------
 | 
	
		
			
				|  |  | - 1 file changed, 5 insertions(+), 10 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -index 5b26b20..a3edf0e 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/windowing/egl/EGLNativeTypeRaspberryPI.cpp
 | 
	
		
			
				|  |  | -@@ -483,10 +483,8 @@ bool CEGLNativeTypeRaspberryPI::ProbeResolutions(std::vector<RESOLUTION_INFO> &r
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(resolutions.size() == 0)
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | --    RESOLUTION_INFO res;
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -     AddUniqueResolution(m_desktopRes, resolutions);
 | 
	
		
			
				|  |  | -+    CLog::Log(LOGDEBUG, "EGL probe resolution %s:%x\n", m_desktopRes.strMode.c_str(), m_desktopRes.dwFlags);
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   if(resolutions.size() < 2)
 | 
	
		
			
				|  |  | -@@ -576,13 +574,12 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -       res.iScreenWidth  = tv->width;
 | 
	
		
			
				|  |  | -       res.iScreenHeight = tv->height;
 | 
	
		
			
				|  |  | -       res.fPixelRatio   = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res.iScreenWidth / (float)res.iScreenHeight);
 | 
	
		
			
				|  |  | -+      res.iSubtitles    = (int)(0.965 * res.iHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+      AddUniqueResolution(res, resolutions);
 | 
	
		
			
				|  |  | -       CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f) %s%s:%x\n", i, res.strMode.c_str(), res.fPixelRatio,
 | 
	
		
			
				|  |  | -           tv->native ? "N" : "", tv->scan_mode ? "I" : "", tv->code);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | --      res.iSubtitles    = (int)(0.965 * res.iHeight);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | --      AddUniqueResolution(res, resolutions);
 | 
	
		
			
				|  |  | -       if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -         RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -@@ -596,11 +593,10 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -         res2.dwFlags |= D3DPRESENTFLAG_MODE3DSBS;
 | 
	
		
			
				|  |  | -         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
 | 
	
		
			
				|  |  | --        CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         AddUniqueResolution(res2, resolutions);
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | -         if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
 | 
	
		
			
				|  |  | -         {
 | 
	
		
			
				|  |  | -           res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
 | 
	
		
			
				|  |  | -@@ -612,11 +608,10 @@ void CEGLNativeTypeRaspberryPI::GetSupportedModes(HDMI_RES_GROUP_T group, std::v
 | 
	
		
			
				|  |  | -         RESOLUTION_INFO res2 = res;
 | 
	
		
			
				|  |  | -         res2.dwFlags |= D3DPRESENTFLAG_MODE3DTB;
 | 
	
		
			
				|  |  | -         res2.fPixelRatio    = get_display_aspect_ratio((HDMI_ASPECT_T)tv->aspect_ratio) / ((float)res2.iScreenWidth / (float)res2.iScreenHeight);
 | 
	
		
			
				|  |  | --        CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | --
 | 
	
		
			
				|  |  | -         res2.iSubtitles    = (int)(0.965 * res2.iHeight);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -         AddUniqueResolution(res2, resolutions);
 | 
	
		
			
				|  |  | -+        CLog::Log(LOGDEBUG, "EGL mode %d: %s (%.2f)\n", i, res2.strMode.c_str(), res2.fPixelRatio);
 | 
	
		
			
				|  |  | -         if (tv->frame_rate == 24 || tv->frame_rate == 30 || tv->frame_rate == 60)
 | 
	
		
			
				|  |  | -         {
 | 
	
		
			
				|  |  | -           res2.fRefreshRate  = (float)tv->frame_rate * (1000.0f/1001.0f);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 9eb0d69eb1f319421780025cefe6df3ade40c4dc Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sat, 7 Jun 2014 16:55:41 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 91/94] [omx] Remove logging for texture jobs
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -This causes a lot of log spam which hasn't proved useful so far.
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/omxplayer/OMXImage.cpp | 5 -----
 | 
	
		
			
				|  |  | - 1 file changed, 5 deletions(-)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/omxplayer/OMXImage.cpp b/xbmc/cores/omxplayer/OMXImage.cpp
 | 
	
		
			
				|  |  | -index 262a004..d529b20 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/omxplayer/OMXImage.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/omxplayer/OMXImage.cpp
 | 
	
		
			
				|  |  | -@@ -210,13 +210,11 @@ bool COMXImage::SendMessage(bool (*callback)(EGLDisplay egl_display, EGLContext
 | 
	
		
			
				|  |  | -   mess.sync.Reset();
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     CSingleLock lock(m_texqueue_lock);
 | 
	
		
			
				|  |  | --    CLog::Log(LOGDEBUG, "%s: texture job: %p:%p", __func__, &mess, mess.callback);
 | 
	
		
			
				|  |  | -     m_texqueue.push(&mess);
 | 
	
		
			
				|  |  | -     m_texqueue_cond.notifyAll();
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | -   // wait for function to have finished (in texture thread)
 | 
	
		
			
				|  |  | -   mess.sync.Wait();
 | 
	
		
			
				|  |  | --  CLog::Log(LOGDEBUG, "%s: texture job done: %p:%p = %d", __func__, &mess, mess.callback, mess.result);
 | 
	
		
			
				|  |  | -   // need to ensure texture thread has returned from mess.sync.Set() before we exit and free tex
 | 
	
		
			
				|  |  | -   CSingleLock lock(m_texqueue_lock);
 | 
	
		
			
				|  |  | -   return mess.result;
 | 
	
		
			
				|  |  | -@@ -429,15 +427,12 @@ void COMXImage::Process()
 | 
	
		
			
				|  |  | -       struct callbackinfo *mess = m_texqueue.front();
 | 
	
		
			
				|  |  | -       m_texqueue.pop();
 | 
	
		
			
				|  |  | -       lock.Leave();
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "%s: texture job: %p:%p:%p", __func__, mess, mess->callback, mess->cookie);
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -       mess->result = mess->callback(g_Windowing.GetEGLDisplay(), GetEGLContext(), mess->cookie);
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "%s: texture job about to Set: %p:%p:%p", __func__, mess, mess->callback, mess->cookie);
 | 
	
		
			
				|  |  | -       {
 | 
	
		
			
				|  |  | -         CSingleLock lock(m_texqueue_lock);
 | 
	
		
			
				|  |  | -         mess->sync.Set();
 | 
	
		
			
				|  |  | -       }
 | 
	
		
			
				|  |  | --      CLog::Log(LOGDEBUG, "%s: texture job: %p done", __func__, mess);
 | 
	
		
			
				|  |  | -     }
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - }
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 4c7a42273416f4053a5bb90755ea45cc0a5f7a0b Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Sun, 15 Jun 2014 13:20:53 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 92/94] gles: Avoid crash when capturing snapshot when using
 | 
	
		
			
				|  |  | - dvdplayer
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Note: snapshot will be blank, but that's better than crashing
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp | 2 ++
 | 
	
		
			
				|  |  | - 1 file changed, 2 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -index e22a153..0cff2c5 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/VideoRenderers/LinuxRendererGLES.cpp
 | 
	
		
			
				|  |  | -@@ -1600,7 +1600,9 @@ bool CLinuxRendererGLES::RenderCapture(CRenderCapture* capture)
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -   // If rendered directly by the hardware
 | 
	
		
			
				|  |  | -+#ifndef TARGET_RASPBERRY_PI
 | 
	
		
			
				|  |  | -   if (m_renderMethod & RENDER_BYPASS)
 | 
	
		
			
				|  |  | -+#endif
 | 
	
		
			
				|  |  | -   {
 | 
	
		
			
				|  |  | -     capture->BeginRender();
 | 
	
		
			
				|  |  | -     capture->EndRender();
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 9805b1c9b218f8ba15c41752cc88f6e8bc3223ad Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 28 May 2014 18:30:51 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 93/94] [omxcodec] Reduce GPU memory use by 2 video frames
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp | 14 ++++++++++++++
 | 
	
		
			
				|  |  | - 1 file changed, 14 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -index 93cf521..cc45570 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/cores/dvdplayer/DVDCodecs/Video/OpenMaxVideo.cpp
 | 
	
		
			
				|  |  | -@@ -308,6 +308,20 @@ bool COpenMaxVideo::Open(CDVDStreamInfo &hints, CDVDCodecOptions &options, OpenM
 | 
	
		
			
				|  |  | -     return false;
 | 
	
		
			
				|  |  | -   }
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  {
 | 
	
		
			
				|  |  | -+    // as we aren't tunnelled to display, we can save memory by setting extrabuffers to 0
 | 
	
		
			
				|  |  | -+    OMX_PARAM_U32TYPE extra_buffers;
 | 
	
		
			
				|  |  | -+    OMX_INIT_STRUCTURE(extra_buffers);
 | 
	
		
			
				|  |  | -+    extra_buffers.nU32 = 0;
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -+    omx_err = m_omx_decoder.SetParameter(OMX_IndexParamBrcmExtraBuffers, &extra_buffers);
 | 
	
		
			
				|  |  | -+    if(omx_err != OMX_ErrorNone)
 | 
	
		
			
				|  |  | -+    {
 | 
	
		
			
				|  |  | -+      CLog::Log(LOGERROR, "COMXVideo::Open error OMX_IndexParamBrcmExtraBuffers omx_err(0x%08x)\n", omx_err);
 | 
	
		
			
				|  |  | -+      return false;
 | 
	
		
			
				|  |  | -+    }
 | 
	
		
			
				|  |  | -+  }
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   // request portsettingschanged on aspect ratio change
 | 
	
		
			
				|  |  | -   OMX_CONFIG_REQUESTCALLBACKTYPE notifications;
 | 
	
		
			
				|  |  | -   OMX_INIT_STRUCTURE(notifications);
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -From 1b49a6f5b1655918e26d84ca4260fc249c00022f Mon Sep 17 00:00:00 2001
 | 
	
		
			
				|  |  | -From: popcornmix <popcornmix@gmail.com>
 | 
	
		
			
				|  |  | -Date: Wed, 18 Jun 2014 23:11:28 +0100
 | 
	
		
			
				|  |  | -Subject: [PATCH 94/94] [rbp] Reduce GPU memory use when limited
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Switching from default triple buffered output to double buffered saves 8M with 1080p GUI.
 | 
	
		
			
				|  |  | -This may slightly reduce framerate, but is likely to be minimal.
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -Assume if gpu_mem is set below the default 128M that this memory reduction is wanted
 | 
	
		
			
				|  |  | ----
 | 
	
		
			
				|  |  | - xbmc/linux/RBP.cpp | 3 +++
 | 
	
		
			
				|  |  | - 1 file changed, 3 insertions(+)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -diff --git a/xbmc/linux/RBP.cpp b/xbmc/linux/RBP.cpp
 | 
	
		
			
				|  |  | -index 9a5e9cb..50d5186 100644
 | 
	
		
			
				|  |  | ---- a/xbmc/linux/RBP.cpp
 | 
	
		
			
				|  |  | -+++ b/xbmc/linux/RBP.cpp
 | 
	
		
			
				|  |  | -@@ -72,6 +72,9 @@ bool CRBP::Initialize()
 | 
	
		
			
				|  |  | -   if (vc_gencmd(response, sizeof response, "codec_enabled WVC1") == 0)
 | 
	
		
			
				|  |  | -     m_codec_wvc1_enabled = strcmp("WVC1=enabled", response) == 0;
 | 
	
		
			
				|  |  | - 
 | 
	
		
			
				|  |  | -+  if (m_gpu_mem < 128)
 | 
	
		
			
				|  |  | -+    setenv("V3D_DOUBLE_BUFFER", "1", 1);
 | 
	
		
			
				|  |  | -+
 | 
	
		
			
				|  |  | -   g_OMXImage.Initialize();
 | 
	
		
			
				|  |  | -   m_omx_image_init = true;
 | 
	
		
			
				|  |  | -   return true;
 | 
	
		
			
				|  |  | --- 
 | 
	
		
			
				|  |  | -1.9.3
 | 
	
		
			
				|  |  | -
 |