linuxserver / docker-tvheadend

GNU General Public License v3.0
158 stars 87 forks source link

[FEAT] Compile libdvbcsa with icam support #249

Closed Chris230291 closed 1 month ago

Chris230291 commented 5 months ago

Is this a new feature request?

Wanted change

TVHeadend can now detect icam support added to libdvbcsa https://github.com/tvheadend/tvheadend/pull/1593 libdvbcsa is outdated and requires patching to support icam. Here is a working example that I am using now, based on your image, but I think it would be better if it was built in. What do you think?

FROM lscr.io/linuxserver/tvheadend:latest

COPY patches/ /tmp/patches/

RUN \
  echo "**** install build packages ****" && \
  apk add --no-cache \
    autoconf \
    automake \
    build-base \
    git \
    libtool

RUN \
  echo "**** compile libdvbcsa ****" && \
  git clone https://github.com/glenvt18/libdvbcsa.git /tmp/libdvbcsa && \
  cd /tmp/libdvbcsa && \
  git checkout 2a1e61e569a621c55c2426f235f42c2398b7f18f && \
  echo "**** patch libdvbcsa ****" && \
  git config apply.whitespace nowarn && git apply /tmp/patches/libdvbcsa.patch && sed 's# == 4)# > 0)#' -i src/dvbcsa_pv.h && \
  ./bootstrap && \
  ./configure \
    --enable-ssse3 \
    --with-pic \
    --prefix=/usr \
    --sysconfdir=/etc \
    --mandir=/usr/share/man \
    --infodir=/usr/share/info \
    --localstatedir=/var && \
  make -j 2 && \
  make check && \
  make DESTDIR=/tmp/libdvbcsa-build install && \
  echo "**** copy to /usr for tvheadend dependency ****" && \
  cp -pr /tmp/libdvbcsa-build/usr/* /usr/

  RUN \
  echo "**** remove build packages ****" && \
  apk del \
    autoconf \
    automake \
    build-base \
    git \
    libtool

And the patch

--- a/README
+++ b/README
@@ -135,6 +135,12 @@ Example:
     dvbcsa_bs_encrypt(key, b, 184);

+    DVBCSA_KEY_ECM
+
+    unsigned char ecm = (ecm_caid >> 8 == 0x09 && (ecm_data[2] - ecm_data[4]) == 4) ? ecm_data[21] : 0;
+    dvbcsa_bs_key_set_ecm(ecm, cw, key);
+
+
 Portability
 ===========

--- a/src/dvbcsa/dvbcsa.h
+++ b/src/dvbcsa/dvbcsa.h
@@ -93,6 +93,11 @@ void dvbcsa_bs_key_free(struct dvbcsa_bs_key_s *key);

 void dvbcsa_bs_key_set(const dvbcsa_cw_t cw, struct dvbcsa_bs_key_s *key);

+#ifndef DVBCSA_KEY_ECM
+#define DVBCSA_KEY_ECM 1
+#endif
+void dvbcsa_bs_key_set_ecm(const unsigned char ecm, const dvbcsa_cw_t cw, struct dvbcsa_bs_key_s *key);
+
 /** get maximum number of packet per batch */

 unsigned int dvbcsa_bs_batch_size(void);
--- a/src/dvbcsa_bs_key.c
+++ b/src/dvbcsa_bs_key.c
@@ -63,3 +63,40 @@ dvbcsa_bs_key_set (const dvbcsa_cw_t cw, struct dvbcsa_bs_key_s *key)
     }
 }

+void
+dvbcsa_bs_key_set_ecm (const unsigned char ecm, const dvbcsa_cw_t cw, struct dvbcsa_bs_key_s *key)
+{
+  dvbcsa_keys_t kk;
+  int i;
+
+  /* precalculations for stream */
+
+  uint64_t ck = dvbcsa_load_le64(cw);
+
+  for (i = 0; i < DVBCSA_CWBITS_SIZE; i++)
+    key->stream[i] = (ck >> (i^4)) & 1 ? BS_VAL8(ff) : BS_VAL8(00);
+
+  /* precalculations for block */
+
+  dvbcsa_key_schedule_block_ecm(ecm, cw, kk);
+
+  for (i = 0; i < DVBCSA_KEYSBUFF_SIZE; i++)
+    {
+#if BS_BATCH_SIZE == 32
+      *(dvbcsa_u32_aliasing_t *)(key->block + i) = kk[i] * 0x01010101;
+
+#elif BS_BATCH_SIZE == 64
+      *(dvbcsa_u64_aliasing_t *)(key->block + i) = kk[i] * 0x0101010101010101ULL;
+
+#elif BS_BATCH_SIZE > 64 && BS_BATCH_SIZE % 64 == 0
+      uint64_t v = kk[i] * 0x0101010101010101ULL;
+      int j;
+
+      for (j = 0; j < BS_BATCH_BYTES / 8; j++)
+        *((dvbcsa_u64_aliasing_t *)(key->block + i) + j) = v;
+#else
+# error
+#endif
+    }
+}
+
--- a/src/dvbcsa_key.c
+++ b/src/dvbcsa_key.c
@@ -585,3 +585,18 @@ dvbcsa_key_schedule_block(const dvbcsa_cw_t cw, uint8_t * kk)
       kk[i*8+j] = (k[i]>>(j*8)) ^ i;
 }

+void
+dvbcsa_key_schedule_block_ecm(const unsigned char ecm, const dvbcsa_cw_t cw, uint8_t * kk)
+{
+  uint64_t k[7];
+  int i, j;
+
+  k[6] = dvbcsa_load_le64_ecm(ecm, cw);
+  for (i = 6; i > 0; i--)
+    k[i - 1] = dvbcsa_key_permute_block(k[i]);
+
+  for (i = 0; i < 7; i++)
+    for (j = 0; j < 8; j++)
+      kk[i*8+j] = (k[i]>>(j*8)) ^ i;
+}
+
--- a/src/dvbcsa_pv.h
+++ b/src/dvbcsa_pv.h
@@ -87,6 +87,25 @@ struct dvbcsa_key_s
 };

 extern const uint8_t dvbcsa_block_sbox[256];
+static const uint8_t csa_block_perm_ecm[256] =
+{
+    0x00, 0x02, 0x80, 0x82, 0x20, 0x22, 0xa0, 0xa2, 0x04, 0x06, 0x84, 0x86, 0x24, 0x26, 0xa4, 0xa6,
+    0x40, 0x42, 0xc0, 0xc2, 0x60, 0x62, 0xe0, 0xe2, 0x44, 0x46, 0xc4, 0xc6, 0x64, 0x66, 0xe4, 0xe6,
+    0x01, 0x03, 0x81, 0x83, 0x21, 0x23, 0xa1, 0xa3, 0x05, 0x07, 0x85, 0x87, 0x25, 0x27, 0xa5, 0xa7,
+    0x41, 0x43, 0xc1, 0xc3, 0x61, 0x63, 0xe1, 0xe3, 0x45, 0x47, 0xc5, 0xc7, 0x65, 0x67, 0xe5, 0xe7,
+    0x08, 0x0a, 0x88, 0x8a, 0x28, 0x2a, 0xa8, 0xaa, 0x0c, 0x0e, 0x8c, 0x8e, 0x2c, 0x2e, 0xac, 0xae,
+    0x48, 0x4a, 0xc8, 0xca, 0x68, 0x6a, 0xe8, 0xea, 0x4c, 0x4e, 0xcc, 0xce, 0x6c, 0x6e, 0xec, 0xee,
+    0x09, 0x0b, 0x89, 0x8b, 0x29, 0x2b, 0xa9, 0xab, 0x0d, 0x0f, 0x8d, 0x8f, 0x2d, 0x2f, 0xad, 0xaf,
+    0x49, 0x4b, 0xc9, 0xcb, 0x69, 0x6b, 0xe9, 0xeb, 0x4d, 0x4f, 0xcd, 0xcf, 0x6d, 0x6f, 0xed, 0xef,
+    0x10, 0x12, 0x90, 0x92, 0x30, 0x32, 0xb0, 0xb2, 0x14, 0x16, 0x94, 0x96, 0x34, 0x36, 0xb4, 0xb6,
+    0x50, 0x52, 0xd0, 0xd2, 0x70, 0x72, 0xf0, 0xf2, 0x54, 0x56, 0xd4, 0xd6, 0x74, 0x76, 0xf4, 0xf6,
+    0x11, 0x13, 0x91, 0x93, 0x31, 0x33, 0xb1, 0xb3, 0x15, 0x17, 0x95, 0x97, 0x35, 0x37, 0xb5, 0xb7,
+    0x51, 0x53, 0xd1, 0xd3, 0x71, 0x73, 0xf1, 0xf3, 0x55, 0x57, 0xd5, 0xd7, 0x75, 0x77, 0xf5, 0xf7,
+    0x18, 0x1a, 0x98, 0x9a, 0x38, 0x3a, 0xb8, 0xba, 0x1c, 0x1e, 0x9c, 0x9e, 0x3c, 0x3e, 0xbc, 0xbe,
+    0x58, 0x5a, 0xd8, 0xda, 0x78, 0x7a, 0xf8, 0xfa, 0x5c, 0x5e, 0xdc, 0xde, 0x7c, 0x7e, 0xfc, 0xfe,
+    0x19, 0x1b, 0x99, 0x9b, 0x39, 0x3b, 0xb9, 0xbb, 0x1d, 0x1f, 0x9d, 0x9f, 0x3d, 0x3f, 0xbd, 0xbf,
+    0x59, 0x5b, 0xd9, 0xdb, 0x79, 0x7b, 0xf9, 0xfb, 0x5d, 0x5f, 0xdd, 0xdf, 0x7d, 0x7f, 0xfd, 0xff
+};

 void dvbcsa_block_decrypt (const dvbcsa_keys_t key, const dvbcsa_block_t in, dvbcsa_block_t out);
 void dvbcsa_block_encrypt (const dvbcsa_keys_t key, const dvbcsa_block_t in, dvbcsa_block_t out);
@@ -95,6 +114,7 @@ void dvbcsa_stream_xor (const dvbcsa_cw_t cw, const dvbcsa_block_t iv,
                         uint8_t *stream, unsigned int len);

 void dvbcsa_key_schedule_block(const dvbcsa_cw_t cw, uint8_t * kk);
+void dvbcsa_key_schedule_block_ecm(const unsigned char ecm, const dvbcsa_cw_t cw, uint8_t * kk);

 DVBCSA_INLINE static inline void
 dvbcsa_xor_64 (uint8_t *b, const uint8_t *a)
@@ -141,6 +161,33 @@ dvbcsa_load_le64(const uint8_t *p)
 #endif
 }

+DVBCSA_INLINE static inline uint64_t
+dvbcsa_load_le64_ecm(const unsigned char ecm, const uint8_t *p)
+{
+  dvbcsa_block_t W;
+  memcpy(W, p, sizeof(W));
+  if (ecm == 4)
+    {
+      W[0] = csa_block_perm_ecm[p[0]];
+      W[4] = csa_block_perm_ecm[p[4]];
+    }
+#if defined(DVBCSA_ENDIAN_LITTLE)
+  uint64_t i;
+  memcpy(&i, W, 8);
+  return i;
+#else
+  return (uint64_t)( ((uint64_t)W[7] << 56) |
+                     ((uint64_t)W[6] << 48) |
+                     ((uint64_t)W[5] << 40) |
+                     ((uint64_t)W[4] << 32) |
+                     ((uint64_t)W[3] << 24) |
+                     ((uint64_t)W[2] << 16) |
+                     ((uint64_t)W[1] << 8 ) |
+                      (uint64_t)W[0]
+                     );
+#endif
+}
+
 DVBCSA_INLINE static inline void
 dvbcsa_store_le64(uint8_t *p, const uint64_t w)
 {

I can only test what I have, and that's amd64. I believe ARM could be made to work like this.

  ./configure \
    --enable-neon \
    --with-pic \
    --prefix=/usr \
    --sysconfdir=/etc \
    --mandir=/usr/share/man \
    --infodir=/usr/share/info \
    --localstatedir=/var && \

Reason for change

Support newer DVB standards

Proposed code change

No response

TonKro commented 4 months ago

Is there a certain setting extra needed? While working with Chris tvheadend docker ICAM support is working. While using this docker it is not working.

NCAM returns found (163 ms) by ForeverCam1 - Sky Sport F1 HD ant the service is not clear

Sometimes it gives:

2024/02/24 15:46:47 7E8978E2 c (dvbapi) Demuxer 0 trying to descramble PID 0 CAID 098D PROVID 000000 ECMPID 1CBA ANY CHID PMTPID 0066 VPID 06FF 2024/02/24 15:47:01 7E8978E2 c (dvbapi) Demuxer 0 stopped descrambling for program 0011 (Sky Sport F1 HD) 2024/02/24 15:47:05 7E8978E2 c (dvbapi) Demuxer 0 ecmpid 0 CAID: 098D ECM_PID: 1CBA PROVID: 000000 2024/02/24 15:47:05 7E8978E2 c (dvbapi) Demuxer 0 ecmpid 1 CAID: 09F0 ECM_PID: 1FBA PROVID: 000000 2024/02/24 15:47:05 7E8978E2 c (dvbapi) Demuxer 0 ecmpid 2 CAID: 098C ECM_PID: 1ABA PROVID: 000000 2024/02/24 15:47:05 7E8978E2 c (dvbapi) Demuxer 0 ecmpid 3 CAID: 09C4 ECM_PID: 1BBA PROVID: 000000

With Chris's docker NCAM adds ICAM and the service is clear.

What am I doing wrong?

Chris230291 commented 4 months ago

iCAM doesn't work with the @LinuxServer image. I opened this issue to see if they would build in the patched libdvbcsa, but no one has replied yet. Until then, you can just use my image… But I don't keep it up to date like these guys do, and It doesn't support multiple architectures.

TonKro commented 4 months ago

Do you have a description how to build tvheadend myself with icam support?

LinuxServer-CI commented 3 months ago

This issue has been automatically marked as stale because it has not had recent activity. This might be due to missing feedback from OP. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] commented 3 days ago

This issue is locked due to inactivity