SRCS += src/cwc.c \
src/capmt.c \
src/krypt.c \
- src/ffdecsa/FFdecsa.c
+ src/ffdecsa/ffdecsa_interface.c \
+ src/ffdecsa/ffdecsa_int.c \
+ src/ffdecsa/ffdecsa_mmx.c \
+ src/ffdecsa/ffdecsa_sse2.c \
-ifneq ($(ARCH), ppc)
-${BUILDDIR}/src/ffdecsa/FFdecsa.o : CFLAGS = -mmmx
-endif
LDFLAGS += -lcrypt
+${BUILDDIR}/src/ffdecsa/ffdecsa_mmx.o : CFLAGS = -mmmx
+${BUILDDIR}/src/ffdecsa/ffdecsa_sse2.o : CFLAGS = -msse2
+
#
# Primary web interface
#
# Common CFLAGS for all files
CFLAGS_com = -g -funsigned-char -O2
CFLAGS_com += -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
-CFLAGS_com += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR} $(CFLAGS_ffdecsa)
+CFLAGS_com += -I${BUILDDIR} -I${CURDIR}/src -I${CURDIR}
all: ${PROG}
ARCH=`uname -m`
OSENV="posix"
PREFIX=/usr/local
-if [ "$ARCH" = "ppc" ] ; then
- PARALLEL_MODE=PARALLEL_32_INT
-else
- PARALLEL_MODE=PARALLEL_64_MMX
-fi
show_help(){
echo "Usage: configure [options]"
echo " --arch=arch Build for this architecture [$ARCH]"
echo " --cpu=cpu Build and optimize for specific CPU"
echo " --cc=CC Build using the given compiler"
- echo " --ffdecsa-mode=MODE Select Mode for ffdecsa"
- echo " PARALLEL_64_MMX (default)"
- echo " PARALLEL_128_SSE2"
echo " --release Stage for release"
exit 1
}
;;
--cc=*) CC="$optval"
;;
- --ffdecsa-mode=*) PARALLEL_MODE="$optval"
- ;;
--enable-?*|--disable-?*)
eval $(echo "$opt" | sed 's/--/action=/;s/-/ option=/;s/-/_/g')
$action $option
fi
fi
-#
-# ffdecsa mode
-#
-echo >>${CONFIG_MAK} "CFLAGS_ffdecsa = -DPARALLEL_MODE=${PARALLEL_MODE}"
-
#
# configure ffmpeg
#
* Add support for configuring a per-channel pre/post extra time for
scheduled recordings. Ticket #104
+ * Autodetect CPU capabilities and choose best mode for CSA descrambler.
+ Ticket #122
+
hts-tvheadend (2.5) hts; urgency=low
* If a previosly detected DVB adapter was not present during startup,
#include <stdio.h>
#include <stdlib.h>
-#include "FFdecsa.h"
-
#ifndef NULL
#define NULL 0
#endif
#define PARALLEL_128_SSE 1285
#define PARALLEL_128_SSE2 1286
-//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice ////////
-#ifndef PARALLEL_MODE
-#define PARALLEL_MODE PARALLEL_64_MMX
-#endif
-//////// our choice //////////////// our choice //////////////// our choice //////////////// our choice ////////
-
#include "parallel_generic.h"
//// conditionals
#if PARALLEL_MODE==PARALLEL_32_4CHAR
#include "parallel_032_4charA.h"
#elif PARALLEL_MODE==PARALLEL_32_INT
#include "parallel_032_int.h"
+#define FUNC(x) (x ## _32int)
#elif PARALLEL_MODE==PARALLEL_64_8CHAR
#include "parallel_064_8char.h"
#elif PARALLEL_MODE==PARALLEL_64_8CHARA
#include "parallel_064_long.h"
#elif PARALLEL_MODE==PARALLEL_64_MMX
#include "parallel_064_mmx.h"
+#define FUNC(x) (x ## _64mmx)
#elif PARALLEL_MODE==PARALLEL_128_16CHAR
#include "parallel_128_16char.h"
#elif PARALLEL_MODE==PARALLEL_128_16CHARA
#include "parallel_128_sse.h"
#elif PARALLEL_MODE==PARALLEL_128_SSE2
#include "parallel_128_sse2.h"
+#define FUNC(x) (x ## _128sse2)
#else
#error "unknown/undefined parallel mode"
#endif
+
// stuff depending on conditionals
#define BYTES_PER_GROUP (GROUP_PARALLELISM/8)
//-----block main function
// block group
-static void block_decypher_group(
+static void block_decypher_group (
batch *kkmulti, // [In] kkmulti[0]-kkmulti[55] 56 batches | Key schedule (each batch has repeated equal bytes).
unsigned char *ib, // [In] (ib0,ib1,...ib7)...x32 32*8 bytes | Initialization vector.
unsigned char *bd, // [Out] (bd0,bd1,...bd7)...x32 32*8 bytes | Block decipher.
//-----------------------------------EXTERNAL INTERFACE
-//-----get internal parallelism
-
-int get_internal_parallelism(void){
- return GROUP_PARALLELISM;
-}
-
-//-----get suggested cluster size
-
-int get_suggested_cluster_size(void){
- int r;
- r=GROUP_PARALLELISM+GROUP_PARALLELISM/10;
- if(r<GROUP_PARALLELISM+5) r=GROUP_PARALLELISM+5;
- return r;
-}
-
-//-----key structure
-
-void *get_key_struct(void){
- struct csa_keys_t *keys=(struct csa_keys_t *)MALLOC(sizeof(struct csa_keys_t));
- if(keys) {
- static const unsigned char pk[8] = { 0,0,0,0,0,0,0,0 };
- set_control_words(keys,pk,pk);
- }
- return keys;
-}
-
-void free_key_struct(void *keys){
- return FREE(keys);
-}
//-----set control words
}
}
-void set_control_words(void *keys, const unsigned char *ev, const unsigned char *od){
+extern void FUNC(set_control_words)(void *keys, const unsigned char *ev, const unsigned char *od);
+
+void FUNC(set_control_words)(void *keys, const unsigned char *ev, const unsigned char *od)
+{
schedule_key(&((struct csa_keys_t *)keys)->even,ev);
schedule_key(&((struct csa_keys_t *)keys)->odd,od);
}
-void set_even_control_word(void *keys, const unsigned char *pk){
+extern void FUNC(set_even_control_word)(void *keys, const unsigned char *pk);
+
+void FUNC(set_even_control_word)(void *keys, const unsigned char *pk)
+{
schedule_key(&((struct csa_keys_t *)keys)->even,pk);
}
-void set_odd_control_word(void *keys, const unsigned char *pk){
+extern void FUNC(set_odd_control_word)(void *keys, const unsigned char *pk);
+
+void FUNC(set_odd_control_word)(void *keys, const unsigned char *pk){
schedule_key(&((struct csa_keys_t *)keys)->odd,pk);
}
+//-----get internal parallelism
+
+extern int FUNC(get_internal_parallelism)(void);
+
+int FUNC(get_internal_parallelism)(void)
+{
+ return GROUP_PARALLELISM;
+}
+
+//-----get suggested cluster size
+
+extern int FUNC(get_suggested_cluster_size)(void);
+
+int FUNC(get_suggested_cluster_size)(void)
+{
+ int r;
+ r=GROUP_PARALLELISM+GROUP_PARALLELISM/10;
+ if(r<GROUP_PARALLELISM+5) r=GROUP_PARALLELISM+5;
+ return r;
+}
+
+//-----key structure
+
+extern void *FUNC(get_key_struct)(void);
+void *FUNC(get_key_struct)(void)
+{
+ struct csa_keys_t *keys=(struct csa_keys_t *)MALLOC(sizeof(struct csa_keys_t));
+ if(keys) {
+ static const unsigned char pk[8] = { 0,0,0,0,0,0,0,0 };
+ FUNC(set_control_words)(keys,pk,pk);
+ }
+ return keys;
+}
+
+extern void FUNC(free_key_struct)(void *keys);
+void FUNC(free_key_struct)(void *keys)
+{
+ return FREE(keys);
+}
+
+
+
//-----get control words
#if 0
void get_control_words(void *keys, unsigned char *even, unsigned char *odd){
//----- decrypt
-int decrypt_packets(void *keys, unsigned char **cluster){
+extern int FUNC(decrypt_packets)(void *keys, unsigned char **cluster);
+int FUNC(decrypt_packets)(void *keys, unsigned char **cluster)
+{
// statistics, currently unused
int stat_no_scramble=0;
int stat_reserved=0;
// Please read doc/how_to_use.txt.
int decrypt_packets(void *keys, unsigned char **cluster);
+void ffdecsa_init(void);
+
#endif
--- /dev/null
+#define PARALLEL_MODE PARALLEL_32_INT
+#include "FFdecsa.c"
--- /dev/null
+/*
+ * CPU detection code, extracted from mmx.h
+ * (c)1997-99 by H. Dietz and R. Fisher
+ * Converted to C and improved by Fabrice Bellard.
+ *
+ * This file is part of Tvheadend.
+ *
+ * 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 3 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "tvhead.h"
+#include "FFdecsa.h"
+
+
+
+typedef struct {
+ int (*get_internal_parallelism)(void);
+ int (*get_suggested_cluster_size)(void);
+ void *(*get_key_struct)(void);
+ void (*free_key_struct)(void *keys);
+ void (*set_control_words)(void *keys, const unsigned char *even, const unsigned char *odd);
+
+ void (*set_even_control_word)(void *keys, const unsigned char *even);
+ void (*set_odd_control_word)(void *keys, const unsigned char *odd);
+ int (*decrypt_packets)(void *keys, unsigned char **cluster);
+
+} csafuncs_t;
+
+
+#define MAKEFUNCS(x) \
+extern int get_internal_parallelism_##x(void);\
+extern int get_suggested_cluster_size_##x(void);\
+extern void *get_key_struct_##x(void);\
+extern void free_key_struct_##x(void *keys);\
+extern void set_control_words_##x(void *keys, const unsigned char *even, const unsigned char *odd);\
+extern void set_even_control_word_##x(void *keys, const unsigned char *even);\
+extern void set_odd_control_word_##x(void *keys, const unsigned char *odd);\
+extern int decrypt_packets_##x(void *keys, unsigned char **cluster);\
+static csafuncs_t funcs_##x = { \
+ &get_internal_parallelism_##x,\
+ &get_suggested_cluster_size_##x,\
+ &get_key_struct_##x,\
+ &free_key_struct_##x,\
+ &set_control_words_##x,\
+ &set_even_control_word_##x,\
+ &set_odd_control_word_##x,\
+ &decrypt_packets_##x\
+};
+
+MAKEFUNCS(32int);
+#if defined(__i386__) || defined(__x86_64__)
+MAKEFUNCS(64mmx);
+MAKEFUNCS(128sse2);
+#endif
+
+static csafuncs_t current;
+
+
+
+
+#if defined(__x86_64__)
+# define REG_a "rax"
+# define REG_b "rbx"
+# define REG_c "rcx"
+# define REG_d "rdx"
+# define REG_D "rdi"
+# define REG_S "rsi"
+# define PTR_SIZE "8"
+typedef int64_t x86_reg;
+
+# define REG_SP "rsp"
+# define REG_BP "rbp"
+# define REGBP rbp
+# define REGa rax
+# define REGb rbx
+# define REGc rcx
+# define REGd rdx
+# define REGSP rsp
+
+#elif defined(__i386__)
+
+# define REG_a "eax"
+# define REG_b "ebx"
+# define REG_c "ecx"
+# define REG_d "edx"
+# define REG_D "edi"
+# define REG_S "esi"
+# define PTR_SIZE "4"
+typedef int32_t x86_reg;
+
+# define REG_SP "esp"
+# define REG_BP "ebp"
+# define REGBP ebp
+# define REGa eax
+# define REGb ebx
+# define REGc ecx
+# define REGd edx
+# define REGSP esp
+#else
+typedef int x86_reg;
+#endif
+
+
+
+/* ebx saving is necessary for PIC. gcc seems unable to see it alone */
+#define cpuid(index,eax,ebx,ecx,edx)\
+ __asm__ volatile\
+ ("mov %%"REG_b", %%"REG_S"\n\t"\
+ "cpuid\n\t"\
+ "xchg %%"REG_b", %%"REG_S\
+ : "=a" (eax), "=S" (ebx),\
+ "=c" (ecx), "=d" (edx)\
+ : "0" (index));
+
+
+
+void
+ffdecsa_init(void)
+{
+ current = funcs_32int;
+
+
+#if defined(__i386__) || defined(__x86_64__)
+
+ int eax, ebx, ecx, edx;
+ int max_std_level, std_caps=0;
+
+#if defined(__i386__)
+
+ x86_reg a, c;
+ __asm__ volatile (
+ /* See if CPUID instruction is supported ... */
+ /* ... Get copies of EFLAGS into eax and ecx */
+ "pushfl\n\t"
+ "pop %0\n\t"
+ "mov %0, %1\n\t"
+
+ /* ... Toggle the ID bit in one copy and store */
+ /* to the EFLAGS reg */
+ "xor $0x200000, %0\n\t"
+ "push %0\n\t"
+ "popfl\n\t"
+
+ /* ... Get the (hopefully modified) EFLAGS */
+ "pushfl\n\t"
+ "pop %0\n\t"
+ : "=a" (a), "=c" (c)
+ :
+ : "cc"
+ );
+
+ if (a != c) {
+#endif
+ cpuid(0, max_std_level, ebx, ecx, edx);
+
+ if(max_std_level >= 1){
+ cpuid(1, eax, ebx, ecx, std_caps);
+
+ if (std_caps & (1<<26)) {
+ current = funcs_128sse2;
+ tvhlog(LOG_INFO, "CSA", "Using SSE2 128bit parallel descrambling");
+ return;
+ }
+
+ if (std_caps & (1<<23)) {
+ current = funcs_64mmx;
+ tvhlog(LOG_INFO, "CSA", "Using MMX 64bit parallel descrambling");
+ return;
+ }
+ }
+#if defined(__i386__)
+ }
+#endif
+#endif
+
+ tvhlog(LOG_INFO, "CSA", "Using 32bit parallel descrambling");
+}
+
+
+int
+get_internal_parallelism(void)
+{
+ return current.get_internal_parallelism();
+}
+int
+get_suggested_cluster_size(void)
+{
+ return current.get_suggested_cluster_size();
+}
+
+void *
+get_key_struct(void)
+{
+ return current.get_key_struct();
+}
+void
+free_key_struct(void *keys)
+{
+ current.free_key_struct(keys);
+}
+
+void
+set_even_control_word(void *keys, const unsigned char *even)
+{
+ current.set_even_control_word(keys, even);
+}
+
+void
+set_odd_control_word(void *keys, const unsigned char *odd)
+{
+ current.set_odd_control_word(keys, odd);
+}
+
+int
+decrypt_packets(void *keys, unsigned char **cluster)
+{
+ return current.decrypt_packets(keys, cluster);
+}
--- /dev/null
+#if defined(__i386__) || defined(__x86_64__)
+#define PARALLEL_MODE PARALLEL_64_MMX
+#include "FFdecsa.c"
+#endif
--- /dev/null
+#if defined(__i386__) || defined(__x86_64__)
+#define PARALLEL_MODE PARALLEL_128_SSE2
+#include "FFdecsa.c"
+#endif
#include "v4l.h"
#include "parachute.h"
#include "settings.h"
+#include "ffdecsa/FFdecsa.h"
int running;
extern const char *htsversion;
dvr_init();
htsp_init();
+
+ ffdecsa_init();
if(rawts_input != NULL)
rawts_init(rawts_input);