diff --git a/Makefile b/Makefile
index 100c71f..2151ff1 100644
--- a/Makefile
+++ b/Makefile
@@ -26,7 +26,7 @@ PROG=${BUILDDIR}/tvheadend
 
 CFLAGS += -Wall -Werror -Wwrite-strings -Wno-deprecated-declarations
 CFLAGS += -Wmissing-prototypes
-LDFLAGS += -lrt -ldl
+LDFLAGS += -lrt -ldl -ldvbcsa
 
 #
 # Core
@@ -102,15 +102,15 @@ SRCS-${CONFIG_V4L} += \
 # cwc
 #
 SRCS += src/cwc.c \
-	src/capmt.c \
-	src/ffdecsa/ffdecsa_interface.c \
-	src/ffdecsa/ffdecsa_int.c
+	src/capmt.c # \
+#	src/ffdecsa/ffdecsa_interface.c \
+#	src/ffdecsa/ffdecsa_int.c
 
-SRCS-${CONFIG_MMX}  += src/ffdecsa/ffdecsa_mmx.c
-SRCS-${CONFIG_SSE2} += src/ffdecsa/ffdecsa_sse2.c
+#SRCS-${CONFIG_MMX}  += src/ffdecsa/ffdecsa_mmx.c
+#SRCS-${CONFIG_SSE2} += src/ffdecsa/ffdecsa_sse2.c
 
-${BUILDDIR}/src/ffdecsa/ffdecsa_mmx.o  : CFLAGS = -mmmx
-${BUILDDIR}/src/ffdecsa/ffdecsa_sse2.o : CFLAGS = -msse2
+#${BUILDDIR}/src/ffdecsa/ffdecsa_mmx.o  : CFLAGS = -mmmx
+#${BUILDDIR}/src/ffdecsa/ffdecsa_sse2.o : CFLAGS = -msse2
 
 #
 # Primary web interface
diff --git a/src/capmt.c b/src/capmt.c
index 18cdf2d..f891c9b 100644
--- a/src/capmt.c
+++ b/src/capmt.c
@@ -39,7 +39,7 @@
 #include "tcp.h"
 #include "psi.h"
 #include "tsdemux.h"
-#include "ffdecsa/FFdecsa.h"
+#include <dvbcsa/dvbcsa.h>
 #include "capmt.h"
 #include "notify.h"
 #include "subscriptions.h"
@@ -140,13 +140,18 @@ typedef struct capmt_service {
     CT_FORBIDDEN
   } ct_keystate;
 
-  /* buffer for keystruct */
-  void    *ct_keys;
+  /* buffers for keystructs */
+  struct dvbcsa_bs_key_s *ct_key_even;
+  struct dvbcsa_bs_key_s *ct_key_odd;
 
   /* CSA */
   int      ct_cluster_size;
   uint8_t *ct_tsbcluster;
+  struct dvbcsa_bs_batch_s *ct_tsbbatch_even;
+  struct dvbcsa_bs_batch_s *ct_tsbbatch_odd;
   int      ct_fill;
+  int      ct_fill_even;
+  int      ct_fill_odd;
 
   /* current sequence number */
   uint16_t ct_seq;
@@ -257,7 +262,10 @@ capmt_service_destroy(th_descrambler_t *td)
 
   LIST_REMOVE(ct, ct_link);
 
-  free_key_struct(ct->ct_keys);
+  dvbcsa_bs_key_free(ct->ct_key_odd);
+  dvbcsa_bs_key_free(ct->ct_key_even);
+  free(ct->ct_tsbbatch_odd);
+  free(ct->ct_tsbbatch_even);
   free(ct->ct_tsbcluster);
   free(ct);
 }
@@ -308,9 +316,9 @@ handle_ca0(capmt_t* capmt) {
         continue;
 
       if (memcmp(even, invalid, 8))
-        set_even_control_word(ct->ct_keys, even);
+        dvbcsa_bs_key_set(even, ct->ct_key_even);
       if (memcmp(odd, invalid, 8))
-        set_odd_control_word(ct->ct_keys, odd);
+        dvbcsa_bs_key_set(odd, ct->ct_key_odd);
 
       if(ct->ct_keystate != CT_RESOLVED)
         tvhlog(LOG_INFO, "capmt", "Obtained key for service \"%s\"",t->s_svcname);
@@ -558,8 +566,14 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
      const uint8_t *tsb)
 {
   capmt_service_t *ct = (capmt_service_t *)td;
-  int r, i;
-  unsigned char *vec[3];
+  uint8_t *pkt;
+  int xc0;
+  int ev_od;
+  int len;
+  int offset;
+  int n;
+  // FIXME: //int residue;
+  int i;
   uint8_t *t0;
 
   if(ct->ct_keystate == CT_FORBIDDEN)
@@ -568,28 +582,67 @@ capmt_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *s
   if(ct->ct_keystate != CT_RESOLVED)
     return -1;
 
-  memcpy(ct->ct_tsbcluster + ct->ct_fill * 188, tsb, 188);
+  pkt = ct->ct_tsbcluster + ct->ct_fill * 188;
+  memcpy(pkt, tsb, 188);
   ct->ct_fill++;
 
+  do { // handle this packet
+    xc0 = pkt[3] & 0xc0;
+    if(xc0 == 0x00) { // clear
+      break;
+    }
+    if(xc0 == 0x40) { // reserved
+      break;
+    }
+    if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
+      ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
+      pkt[3] &= 0x3f;  // consider it decrypted now
+      if(pkt[3] & 0x20) { // incomplete packet
+        offset = 4 + pkt[4] + 1;
+        len = 188 - offset;
+        n = len >> 3;
+        // FIXME: //residue = len - (n << 3);
+        if(n == 0) { // decrypted==encrypted!
+          break; // this doesn't need more processing
+        }
+      } else {
+        len = 184;
+        offset = 4;
+        // FIXME: //n = 23;
+        // FIXME: //residue = 0;
+      }
+      if(ev_od == 0) {
+        ct->ct_tsbbatch_even[ct->ct_fill_even].data = pkt + offset;
+        ct->ct_tsbbatch_even[ct->ct_fill_even].len = len;
+        ct->ct_fill_even++;
+      } else {
+        ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = pkt + offset;
+        ct->ct_tsbbatch_odd[ct->ct_fill_odd].len = len;
+        ct->ct_fill_odd++;
+      }
+    }
+  } while(0);
+
   if(ct->ct_fill != ct->ct_cluster_size)
     return 0;
 
-  ct->ct_fill = 0;
-
-  vec[0] = ct->ct_tsbcluster;
-  vec[1] = ct->ct_tsbcluster + ct->ct_cluster_size * 188;
-  vec[2] = NULL;
+  if(ct->ct_fill_even) {
+    ct->ct_tsbbatch_even[ct->ct_fill_even].data = NULL;
+    dvbcsa_bs_decrypt(ct->ct_key_even, ct->ct_tsbbatch_even, 184);
+    ct->ct_fill_even = 0;
+  }
+  if(ct->ct_fill_odd) {
+    ct->ct_tsbbatch_odd[ct->ct_fill_odd].data = NULL;
+    dvbcsa_bs_decrypt(ct->ct_key_odd, ct->ct_tsbbatch_odd, 184);
+    ct->ct_fill_odd = 0;
+  }
 
-  while(1) {
-    t0 = vec[0];
-    r = decrypt_packets(ct->ct_keys, vec);
-    if(r == 0)
-      break;
-    for(i = 0; i < r; i++) {
+    t0 = ct->ct_tsbcluster;
+    for(i = 0; i < ct->ct_fill; i++) {
       ts_recv_packet2(t, t0);
       t0 += 188;
     }
-  }
+  ct->ct_fill = 0;
   return 0;
 }
 
@@ -617,10 +670,14 @@ capmt_service_start(service_t *t)
     elementary_stream_t *st;
 
     /* create new capmt service */
-    ct                  = calloc(1, sizeof(capmt_service_t));
-    ct->ct_cluster_size = get_suggested_cluster_size();
-    ct->ct_tsbcluster   = malloc(ct->ct_cluster_size * 188);
-    ct->ct_seq          = capmt->capmt_seq++;
+    ct                   = calloc(1, sizeof(capmt_service_t));
+    ct->ct_cluster_size  = dvbcsa_bs_batch_size();
+    ct->ct_tsbcluster    = malloc(ct->ct_cluster_size * 188);
+    ct->ct_tsbbatch_even = malloc((ct->ct_cluster_size + 1) *
+                             sizeof(struct dvbcsa_bs_batch_s));
+    ct->ct_tsbbatch_odd  = malloc((ct->ct_cluster_size + 1) *
+                             sizeof(struct dvbcsa_bs_batch_s));
+    ct->ct_seq           = capmt->capmt_seq++;
 
     TAILQ_FOREACH(st, &t->s_components, es_link) {
       caid_t *c = LIST_FIRST(&st->es_caids);
@@ -640,7 +697,8 @@ capmt_service_start(service_t *t)
       ct->ct_caid_last = -1;
     }
 
-    ct->ct_keys       = get_key_struct();
+    ct->ct_key_even   = dvbcsa_bs_key_alloc();
+    ct->ct_key_odd    = dvbcsa_bs_key_alloc();
     ct->ct_capmt      = capmt;
     ct->ct_service  = t;
 
diff --git a/src/cwc.c b/src/cwc.c
index 0ace6de..c17affa 100644
--- a/src/cwc.c
+++ b/src/cwc.c
@@ -32,7 +32,7 @@
 #include "tcp.h"
 #include "psi.h"
 #include "tsdemux.h"
-#include "ffdecsa/FFdecsa.h"
+#include <dvbcsa/dvbcsa.h>
 #include "cwc.h"
 #include "notify.h"
 #include "atomic.h"
@@ -153,7 +153,8 @@ typedef struct cwc_service {
     CS_FORBIDDEN
   } cs_keystate;
 
-  void *cs_keys;
+  struct dvbcsa_bs_key_s *cs_key_even;
+  struct dvbcsa_bs_key_s *cs_key_odd;
 
 
   uint8_t cs_cw[16];
@@ -164,7 +165,11 @@ typedef struct cwc_service {
    */
   int cs_cluster_size;
   uint8_t *cs_tsbcluster;
+  struct dvbcsa_bs_batch_s *cs_tsbbatch_even;
+  struct dvbcsa_bs_batch_s *cs_tsbbatch_odd;
   int cs_fill;
+  int cs_fill_even;
+  int cs_fill_odd;
 
   LIST_HEAD(, ecm_pid) cs_pids;
 
@@ -1661,13 +1666,13 @@ update_keys(cwc_service_t *ct)
   ct->cs_pending_cw_update = 0;
   for(i = 0; i < 8; i++)
     if(ct->cs_cw[i]) {
-      set_even_control_word(ct->cs_keys, ct->cs_cw);
+      dvbcsa_bs_key_set(ct->cs_cw, ct->cs_key_even);
       break;
     }
   
   for(i = 0; i < 8; i++)
     if(ct->cs_cw[8 + i]) {
-      set_odd_control_word(ct->cs_keys, ct->cs_cw + 8);
+      dvbcsa_bs_key_set(ct->cs_cw + 8, ct->cs_key_odd);
       break;
     }
 }
@@ -1681,8 +1686,13 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
 	       const uint8_t *tsb)
 {
   cwc_service_t *ct = (cwc_service_t *)td;
-  int r;
-  unsigned char *vec[3];
+  uint8_t *pkt;
+  int xc0;
+  int ev_od;
+  int len;
+  int offset;
+  int n;
+  // FIXME: //int residue;
 
   if(ct->cs_keystate == CS_FORBIDDEN)
     return 1;
@@ -1693,42 +1703,72 @@ cwc_descramble(th_descrambler_t *td, service_t *t, struct elementary_stream *st,
   if(ct->cs_fill == 0 && ct->cs_pending_cw_update)
     update_keys(ct);
 
-  memcpy(ct->cs_tsbcluster + ct->cs_fill * 188, tsb, 188);
+  pkt = ct->cs_tsbcluster + ct->cs_fill * 188;
+  memcpy(pkt, tsb, 188);
   ct->cs_fill++;
 
+  do { // handle this packet
+    xc0 = pkt[3] & 0xc0;
+    if(xc0 == 0x00) { // clear
+      break;
+    }
+    if(xc0 == 0x40) { // reserved
+      break;
+    }
+    if(xc0 == 0x80 || xc0 == 0xc0) { // encrypted
+      ev_od = (xc0 & 0x40) >> 6; // 0 even, 1 odd
+      pkt[3] &= 0x3f;  // consider it decrypted now
+      if(pkt[3] & 0x20) { // incomplete packet
+        offset = 4 + pkt[4] + 1;
+        len = 188 - offset;
+        n = len >> 3;
+        // FIXME: //residue = len - (n << 3);
+        if(n == 0) { // decrypted==encrypted!
+          break; // this doesn't need more processing
+        }
+      } else {
+        len = 184;
+        offset = 4;
+        // FIXME: //n = 23;
+        // FIXME: //residue = 0;
+      }
+      if(ev_od == 0) {
+        ct->cs_tsbbatch_even[ct->cs_fill_even].data = pkt + offset;
+        ct->cs_tsbbatch_even[ct->cs_fill_even].len = len;
+        ct->cs_fill_even++;
+      } else {
+        ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = pkt + offset;
+        ct->cs_tsbbatch_odd[ct->cs_fill_odd].len = len;
+        ct->cs_fill_odd++;
+      }
+    }
+  } while(0);
+
   if(ct->cs_fill != ct->cs_cluster_size)
     return 0;
 
-  while(1) {
+  if(ct->cs_fill_even) {
+    ct->cs_tsbbatch_even[ct->cs_fill_even].data = NULL;
+    dvbcsa_bs_decrypt(ct->cs_key_even, ct->cs_tsbbatch_even, 184);
+    ct->cs_fill_even = 0;
+  }
+  if(ct->cs_fill_odd) {
+    ct->cs_tsbbatch_odd[ct->cs_fill_odd].data = NULL;
+    dvbcsa_bs_decrypt(ct->cs_key_odd, ct->cs_tsbbatch_odd, 184);
+    ct->cs_fill_odd = 0;
+  }
 
-    vec[0] = ct->cs_tsbcluster;
-    vec[1] = ct->cs_tsbcluster + ct->cs_fill * 188;
-    vec[2] = NULL;
-    
-    r = decrypt_packets(ct->cs_keys, vec);
-    if(r > 0) {
+  {
       int i;
       const uint8_t *t0 = ct->cs_tsbcluster;
 
-      for(i = 0; i < r; i++) {
+      for(i = 0; i < ct->cs_fill; i++) {
 	ts_recv_packet2(t, t0);
 	t0 += 188;
       }
-
-      r = ct->cs_fill - r;
-      assert(r >= 0);
-
-      if(r > 0)
-	memmove(ct->cs_tsbcluster, t0, r * 188);
-      ct->cs_fill = r;
-
-      if(ct->cs_pending_cw_update && r > 0)
-	continue;
-    } else {
-      ct->cs_fill = 0;
-    }
-    break;
   }
+  ct->cs_fill = 0;
+
   if(ct->cs_pending_cw_update)
     update_keys(ct);
 
@@ -1757,7 +1797,10 @@ cwc_service_destroy(th_descrambler_t *td)
 
   LIST_REMOVE(ct, cs_link);
 
-  free_key_struct(ct->cs_keys);
+  dvbcsa_bs_key_free(ct->cs_key_odd);
+  dvbcsa_bs_key_free(ct->cs_key_even);
+  free(ct->cs_tsbbatch_odd);
+  free(ct->cs_tsbbatch_even);
   free(ct->cs_tsbcluster);
   free(ct);
 }
@@ -1802,10 +1845,15 @@ cwc_service_start(service_t *t)
       continue;
 
     ct = calloc(1, sizeof(cwc_service_t));
-    ct->cs_cluster_size = get_suggested_cluster_size();
+    ct->cs_cluster_size = dvbcsa_bs_batch_size();
     ct->cs_tsbcluster = malloc(ct->cs_cluster_size * 188);
+    ct->cs_tsbbatch_even = malloc((ct->cs_cluster_size + 1) *
+                             sizeof(struct dvbcsa_bs_batch_s));
+    ct->cs_tsbbatch_odd = malloc((ct->cs_cluster_size + 1) *
+                            sizeof(struct dvbcsa_bs_batch_s));
 
-    ct->cs_keys = get_key_struct();
+    ct->cs_key_even = dvbcsa_bs_key_alloc();
+    ct->cs_key_odd = dvbcsa_bs_key_alloc();
     ct->cs_cwc = cwc;
     ct->cs_service = t;
     ct->cs_okchannel = -1;
diff --git a/src/main.c b/src/main.c
index 370bb2a..f38a2e6 100644
--- a/src/main.c
+++ b/src/main.c
@@ -57,7 +57,6 @@
 #include "v4l.h"
 #include "trap.h"
 #include "settings.h"
-#include "ffdecsa/FFdecsa.h"
 
 int running;
 extern const char *htsversion;
@@ -401,8 +400,6 @@ main(int argc, char **argv)
 
   htsp_init();
 
-  ffdecsa_init();
-  
   if(rawts_input != NULL)
     rawts_init(rawts_input);
 
