]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
mpegts: add full DTMB network/mux support, issue #4717
authorJaroslav Kysela <perex@perex.cz>
Fri, 10 Nov 2017 09:05:03 +0000 (10:05 +0100)
committerJaroslav Kysela <perex@perex.cz>
Fri, 10 Nov 2017 09:05:03 +0000 (10:05 +0100)
src/input/mpegts/dvb.h
src/input/mpegts/dvb_support.c
src/input/mpegts/linuxdvb/linuxdvb_frontend.c
src/input/mpegts/mpegts_dvb.h
src/input/mpegts/mpegts_mux_dvb.c
src/input/mpegts/mpegts_network_dvb.c

index f169ffff4d75aa82ea8939a4fb4189266422368c..cc0a92bb0c3e6dee6277c9878163cbcf80ca4df4 100644 (file)
@@ -416,6 +416,7 @@ typedef enum dvb_fe_type {
   DVB_TYPE_ISDB_T,              /* terrestrial - japan, brazil */
   DVB_TYPE_ISDB_C,              /* cable - japan, brazil */
   DVB_TYPE_ISDB_S,              /* satellite - japan, brazil */
+  DVB_TYPE_DTMB,                /* DTMB - china, cuba, hong kong, macau */
   DVB_TYPE_DAB,                 /* digital radio (europe) */
   DVB_TYPE_LAST = DVB_TYPE_DAB
 } dvb_fe_type_t;
index d475c544964875adeb9e3133b16e61ca61c408c2..360bf3818b965133030bae2f08474b94bbaa8081 100644 (file)
@@ -728,7 +728,6 @@ dvb_delsys2type ( mpegts_network_t *ln, dvb_fe_delivery_system_t delsys )
     case DVB_SYS_DVBT:
     case DVB_SYS_DVBT2:
     case DVB_SYS_TURBO:
-    case DVB_SYS_DTMB:
       return DVB_TYPE_T;
     case DVB_SYS_DVBS:
     case DVB_SYS_DVBS2:
@@ -747,6 +746,8 @@ dvb_delsys2type ( mpegts_network_t *ln, dvb_fe_delivery_system_t delsys )
       return DVB_TYPE_ISDB_C;
     case DVB_SYS_ISDBS:
       return DVB_TYPE_ISDB_S;
+    case DVB_SYS_DTMB:
+      return DVB_TYPE_DTMB;
     case DVB_SYS_DAB:
       return DVB_TYPE_DAB;
     default:
index 0504cbffd3e8733ab5ee0db8ce50215206a0bb9c..2e8730231edf7b252d72c9e7c195d87badbb2425 100644 (file)
@@ -453,6 +453,16 @@ const idclass_t linuxdvb_frontend_isdb_s_class =
   }
 };
 
+const idclass_t linuxdvb_frontend_dtmb_class =
+{
+  .ic_super      = &linuxdvb_frontend_class,
+  .ic_class      = "linuxdvb_frontend_dab",
+  .ic_caption    = N_("TV Adapters - DTMB Frontend"),
+  .ic_properties = (const property_t[]){
+    {}
+  }
+};
+
 const idclass_t linuxdvb_frontend_dab_class =
 {
   .ic_super      = &linuxdvb_frontend_class,
@@ -1741,6 +1751,7 @@ linuxdvb_frontend_tune0
   p.inversion                = TR(inversion, inv_tbl, INVERSION_AUTO);
   switch (dmc->dmc_fe_type) {
   case DVB_TYPE_T:
+  case DVB_TYPE_DTMB:
 #define _OFDM(xyz) p.u.ofdm.xyz
     _OFDM(bandwidth)         = TRU(ofdm.bandwidth, bw_tbl, BANDWIDTH_AUTO);
     _OFDM(code_rate_HP)      = TRU(ofdm.code_rate_HP, fec_tbl, FEC_AUTO);
@@ -1809,7 +1820,7 @@ linuxdvb_frontend_tune0
   S2CMD(DTV_INVERSION,       p.inversion);
 
   /* DVB-T */
-  if (lfe->lfe_type == DVB_TYPE_T) {
+  if (lfe->lfe_type == DVB_TYPE_T || lfe->lfe_type == DVB_TYPE_DTMB) {
     S2CMD(DTV_BANDWIDTH_HZ,      dvb_bandwidth(dmc->u.dmc_fe_ofdm.bandwidth));
 #if DVB_VER_ATLEAST(5,1)
     S2CMD(DTV_CODE_RATE_HP,      p.u.ofdm.code_rate_HP);
@@ -2101,6 +2112,8 @@ linuxdvb_frontend_create
     idc = &linuxdvb_frontend_isdb_c_class;
   else if (type == DVB_TYPE_ISDB_S)
     idc = &linuxdvb_frontend_isdb_s_class;
+  else if (type == DVB_TYPE_DTMB)
+    idc = &linuxdvb_frontend_dtmb_class;
   else if (type == DVB_TYPE_DAB)
     idc = &linuxdvb_frontend_dab_class;
   else {
index f22e8b0b9c8c93683ea49c1a52e7a915deda3ebc..43e163453a351a90cdcaf15e8ae50a5430160db8 100644 (file)
@@ -53,6 +53,7 @@ extern const idclass_t dvb_network_atsc_c_class;
 extern const idclass_t dvb_network_isdb_t_class;
 extern const idclass_t dvb_network_isdb_c_class;
 extern const idclass_t dvb_network_isdb_s_class;
+extern const idclass_t dvb_network_dtmb_class;
 extern const idclass_t dvb_network_dab_class;
 
 void dvb_network_init ( void );
@@ -90,6 +91,7 @@ extern const idclass_t dvb_mux_atsc_c_class;
 extern const idclass_t dvb_mux_isdb_t_class;
 extern const idclass_t dvb_mux_isdb_c_class;
 extern const idclass_t dvb_mux_isdb_s_class;
+extern const idclass_t dvb_mux_dtmb_class;
 extern const idclass_t dvb_mux_dab_class;
 
 dvb_mux_t *dvb_mux_create0
index 2b6be736fef0f68fa861f25a0d0d99df5fb58f7d..668fe4d33e150fa8182a80a3d738a4d3cf3410ca 100644 (file)
@@ -180,7 +180,6 @@ dvb_mux_dvbt_class_delsys_enum (void *o, const char *lang)
   htsmsg_add_str(list, NULL, dvb_delsys2str(DVB_SYS_DVBT));
   htsmsg_add_str(list, NULL, dvb_delsys2str(DVB_SYS_DVBT2));
   htsmsg_add_str(list, NULL, dvb_delsys2str(DVB_SYS_TURBO));
-  htsmsg_add_str(list, NULL, dvb_delsys2str(DVB_SYS_DTMB));
   return list;
 }
 
@@ -853,6 +852,138 @@ const idclass_t dvb_mux_isdb_s_class =
   }
 };
 
+/*
+ * DTMB, fixme: review actually used parameters!
+ */
+
+dvb_mux_class_X(dtmb, ofdm, bandwidth, bw, bw,
+                     DVB_BANDWIDTH_AUTO,  DVB_BANDWIDTH_10_MHZ,
+                     DVB_BANDWIDTH_8_MHZ, DVB_BANDWIDTH_7_MHZ,
+                     DVB_BANDWIDTH_6_MHZ, DVB_BANDWIDTH_5_MHZ,
+                     DVB_BANDWIDTH_1_712_MHZ);
+dvb_mux_class_R(dtmb, modulation, qam, qam,
+                     DVB_MOD_QAM_AUTO, DVB_MOD_QPSK, DVB_MOD_QAM_16,
+                     DVB_MOD_QAM_64, DVB_MOD_QAM_256);
+dvb_mux_class_X(dtmb, ofdm, transmission_mode, mode, mode,
+                     DVB_TRANSMISSION_MODE_AUTO, DVB_TRANSMISSION_MODE_32K,
+                     DVB_TRANSMISSION_MODE_16K, DVB_TRANSMISSION_MODE_8K,
+                     DVB_TRANSMISSION_MODE_2K, DVB_TRANSMISSION_MODE_1K);
+dvb_mux_class_X(dtmb, ofdm, guard_interval, guard, guard,
+                     DVB_GUARD_INTERVAL_AUTO, DVB_GUARD_INTERVAL_1_32,
+                     DVB_GUARD_INTERVAL_1_16, DVB_GUARD_INTERVAL_1_8,
+                     DVB_GUARD_INTERVAL_1_4, DVB_GUARD_INTERVAL_1_128,
+                     DVB_GUARD_INTERVAL_19_128, DVB_GUARD_INTERVAL_19_256);
+dvb_mux_class_X(dtmb, ofdm, hierarchy_information, hier, hier,
+                     DVB_HIERARCHY_AUTO, DVB_HIERARCHY_NONE,
+                     DVB_HIERARCHY_1, DVB_HIERARCHY_2, DVB_HIERARCHY_4);
+dvb_mux_class_X(dtmb, ofdm, code_rate_HP, fechi, fechi,
+                     DVB_FEC_AUTO, DVB_FEC_1_2, DVB_FEC_2_3, DVB_FEC_3_4,
+                     DVB_FEC_3_5,  DVB_FEC_4_5, DVB_FEC_5_6, DVB_FEC_7_8);
+dvb_mux_class_X(dtmb, ofdm, code_rate_LP, feclo, feclo,
+                     DVB_FEC_AUTO, DVB_FEC_1_2, DVB_FEC_2_3, DVB_FEC_3_4,
+                     DVB_FEC_3_5,  DVB_FEC_4_5, DVB_FEC_5_6, DVB_FEC_7_8);
+
+#define dvb_mux_dtmb_class_delsys_get dvb_mux_class_delsys_get
+#define dvb_mux_dtmb_class_delsys_set dvb_mux_class_delsys_set
+
+static htsmsg_t *
+dvb_mux_dtmb_class_delsys_enum (void *o, const char *lang)
+{
+  htsmsg_t *list = htsmsg_create_list();
+  htsmsg_add_str(list, NULL, dvb_delsys2str(DVB_SYS_DTMB));
+  return list;
+}
+
+static int
+dvb_mux_dtmb_class_frequency_set ( void *o, const void *v )
+{
+  dvb_mux_t *lm = o;
+  uint32_t val = *(uint32_t *)v;
+
+  if (val < 1000)
+    val *= 1000000;
+  else if (val < 1000000)
+    val *= 1000;
+
+  if (val != lm->lm_tuning.dmc_fe_freq) {
+    lm->lm_tuning.dmc_fe_freq = val;
+    return 1;
+  }
+  return 0;
+}
+
+const idclass_t dvb_mux_dtmb_class =
+{
+  .ic_super      = &dvb_mux_class,
+  .ic_class      = "dvb_mux_dtmb",
+  .ic_caption    = N_("DTMB multiplex"),
+  .ic_properties = (const property_t[]){
+    {
+      MUX_PROP_STR("delsys", N_("Delivery system"), dtmb, delsys, "DVBT"),
+      .desc     = N_("The delivery system the mux uses. "
+                     "Make sure that your tuner supports the delivery "
+                     "system selected here."),
+    },
+    {
+      .type     = PT_U32,
+      .id       = "frequency",
+      .name     = N_("Frequency (Hz)"),
+      .desc     = N_("The frequency of the mux (in Hertz)."),
+      .off      = offsetof(dvb_mux_t, lm_tuning.dmc_fe_freq),
+      .set      = dvb_mux_dtmb_class_frequency_set,
+    },
+    {
+      MUX_PROP_STR("bandwidth", N_("Bandwidth"), dtmb, bw, N_("AUTO")),
+      .desc     = N_("The bandwidth the mux uses. "
+                     "If you're not sure of the value leave as AUTO "
+                     "but be aware that tuning may fail as some drivers "
+                     "do not like the AUTO setting."),
+    },
+    {
+      MUX_PROP_STR("constellation", N_("Constellation"), dtmb, qam, N_("AUTO")),
+      .desc     = N_("The COFDM modulation used by the mux. "
+                     "If you're not sure of the value leave as AUTO."),
+    },
+    {
+      MUX_PROP_STR("transmission_mode", N_("Transmission mode"), dtmb, mode, N_("AUTO")),
+      .desc     = N_("The transmission/OFDM mode used by the mux. "
+                     "If you're not sure of the value leave as AUTO "
+                     "but be aware that tuning may fail as some drivers "
+                     "do not like the AUTO setting."),
+    },
+    {
+      MUX_PROP_STR("guard_interval", N_("Guard interval"), dtmb, guard, N_("AUTO")),
+      .desc     = N_("The guard interval used by the mux. "
+                     "If you're not sure of the value leave as AUTO."),
+    },
+    {
+      MUX_PROP_STR("hierarchy", N_("Hierarchy"), dtmb, hier, N_("AUTO")),
+      .desc     = N_("The hierarchical modulation used by the mux. "
+                     "Most people will not need to change this setting."),
+    },
+    {
+      MUX_PROP_STR("fec_hi", N_("FEC high"), dtmb, fechi, N_("AUTO")),
+      .desc     = N_("The forward error correction high value. "
+                     "Most people will not need to change this setting."),
+    },
+    {
+      MUX_PROP_STR("fec_lo", N_("FEC low"), dtmb, feclo, N_("AUTO")),
+      .desc     = N_("The forward error correction low value. "
+                     "Most people will not need to change this setting."),
+    },
+    {
+      .type     = PT_INT,
+      .id       = "plp_id",
+      .name     = N_("PLP ID"),
+      .desc     = N_("The physical layer pipe ID. "
+                     "Most people will not need to change this setting."),
+      .off      = offsetof(dvb_mux_t, lm_tuning.dmc_fe_stream_id),
+      .def.i   = DVB_NO_STREAM_ID_FILTER,
+    },
+    {}
+  }
+};
+
 /*
  * DAB
  */
@@ -1011,6 +1142,9 @@ dvb_mux_create0
   } else if (ln->ln_type == DVB_TYPE_ISDB_S) {
     idc = &dvb_mux_isdb_s_class;
     delsys = DVB_SYS_ISDBS;
+  } else if (ln->ln_type == DVB_TYPE_DTMB) {
+    idc = &dvb_mux_dtmb_class;
+    delsys = DVB_SYS_DTMB;
   } else if (ln->ln_type == DVB_TYPE_DAB) {
     idc = &dvb_mux_dab_class;
     delsys = DVB_SYS_DAB;
index 9ef1e48393d7a47f4952367230de879f1f884d83..88d5d6ad8615372e0d996573300e9231715dad32 100644 (file)
@@ -140,6 +140,8 @@ dvb_network_class_scanfile_list0
     type = "isdb-c";
   else if (clazz == &dvb_network_isdb_s_class)
     type = "isdb-s";
+  else if (clazz == &dvb_network_dtmb_class)
+    type = "dtmb";
   else if (clazz == &dvb_network_dab_class)
     type = "dab";
   else
@@ -174,6 +176,7 @@ SCANFILE_LIST(atsc_c);
 SCANFILE_LIST(isdb_t);
 SCANFILE_LIST(isdb_c);
 SCANFILE_LIST(isdb_s);
+SCANFILE_LIST(dtmb);
 SCANFILE_LIST(dab);
 
 static const void *
@@ -424,6 +427,29 @@ const idclass_t dvb_network_isdb_s_class =
   }
 };
 
+const idclass_t dvb_network_dtmb_class =
+{
+  .ic_super      = &dvb_network_class,
+  .ic_class      = "dvb_network_dtmb",
+  .ic_caption    = N_("DTMB Network"),
+  .ic_properties = (const property_t[]) {
+    {
+      .type     = PT_STR,
+      .id       = "scanfile",
+      .name     = N_("Pre-defined muxes"),
+      .desc     = N_("Use a pre-defined list of DTMB muxes. "
+                     "Note: these lists can sometimes be outdated and "
+                     "may cause scanning to take longer than usual."),
+      .doc      = prop_doc_predefinedmuxlist,
+      .set      = dvb_network_class_scanfile_set,
+      .get      = dvb_network_class_scanfile_get,
+      .list     = dvb_network_class_scanfile_list_dtmb,
+      .opts     = PO_NOSAVE,
+    },
+    {}
+  }
+};
+
 const idclass_t dvb_network_dab_class =
 {
   .ic_super      = &dvb_network_class,
@@ -465,6 +491,7 @@ dvb_network_check_symbol_rate( dvb_mux_t *lm, dvb_mux_conf_t *dmc, int deltar )
 {
   switch (dmc->dmc_fe_type) {
   case DVB_TYPE_T:
+  case DVB_TYPE_DTMB:
     return dvb_network_check_bandwidth(lm->lm_tuning.u.dmc_fe_ofdm.bandwidth,
                                        dmc->u.dmc_fe_ofdm.bandwidth);
   case DVB_TYPE_C:
@@ -607,6 +634,8 @@ dvb_network_mux_class
     return &dvb_mux_isdb_c_class;
   if (idnode_is_instance(&mn->mn_id, &dvb_network_isdb_s_class))
     return &dvb_mux_isdb_s_class;
+  if (idnode_is_instance(&mn->mn_id, &dvb_network_dtmb_class))
+    return &dvb_mux_dtmb_class;
   if (idnode_is_instance(&mn->mn_id, &dvb_network_dab_class))
     return &dvb_mux_dab_class;
   return NULL;
@@ -668,6 +697,7 @@ dvb_network_create_mux
     save |= cls == &dvb_mux_dvbs_class && dmc->dmc_fe_type == DVB_TYPE_S;
     save |= cls == &dvb_mux_atsc_t_class && dmc->dmc_fe_type == DVB_TYPE_ATSC_T;
     save |= cls == &dvb_mux_atsc_c_class && dmc->dmc_fe_type == DVB_TYPE_ATSC_C;
+    save |= cls == &dvb_mux_dtmb_class && dmc->dmc_fe_type == DVB_TYPE_DTMB;
     if (save && dmc->dmc_fe_type == DVB_TYPE_S) {
       satpos = dvb_network_get_orbital_pos(mn);
       /* do not allow to mix satellite positions */
@@ -737,6 +767,7 @@ dvb_network_create_mux
     save |= COMPAREN(dmc_fe_pilot, CBIT_PILOT);
     switch (dmc->dmc_fe_type) {
     case DVB_TYPE_T:
+    case DVB_TYPE_DTMB:
       save |= COMPARE(dmc_fe_stream_id, CBIT_STREAM_ID);
       save |= COMPAREN(u.dmc_fe_ofdm.bandwidth, CBIT_BANDWIDTH);
       save |= COMPAREN(u.dmc_fe_ofdm.hierarchy_information, CBIT_HIERARCHY);
@@ -972,6 +1003,8 @@ const idclass_t *dvb_network_class_by_fe_type(dvb_fe_type_t type)
     return &dvb_network_isdb_c_class;
   else if (type == DVB_TYPE_ISDB_S)
     return &dvb_network_isdb_s_class;
+  else if (type == DVB_TYPE_DTMB)
+    return &dvb_network_dtmb_class;
   else if (type == DVB_TYPE_DAB)
     return &dvb_network_dab_class;
 
@@ -996,6 +1029,8 @@ dvb_fe_type_t dvb_fe_type_by_network_class(const idclass_t *idc)
     return DVB_TYPE_ISDB_C;
   else if (idc == &dvb_network_isdb_s_class)
     return DVB_TYPE_ISDB_S;
+  else if (idc == &dvb_network_dtmb_class)
+    return DVB_TYPE_DTMB;
   else if (idc == &dvb_network_dab_class)
     return DVB_TYPE_DAB;