From c073538e05fda3ca83b11073038b1af527c17bee Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 11 Sep 2014 15:27:01 +0200 Subject: [PATCH] channel number: add minor number handling for ATSC --- src/channels.c | 7 ++-- src/channels.h | 7 +++- src/htsp_server.c | 5 ++- src/input/mpegts.h | 3 +- src/input/mpegts/dvb_psi.c | 6 ++-- src/input/mpegts/mpegts_service.c | 15 ++++++-- src/prop.c | 57 ++++++++++++++++++++++++++----- src/prop.h | 5 +-- src/service.c | 4 +-- src/service.h | 4 +-- src/webui/statedump.c | 13 +++++-- src/webui/static/app/idnode.js | 12 +++++++ 12 files changed, 108 insertions(+), 30 deletions(-) diff --git a/src/channels.c b/src/channels.c index a8921116..4c5eb837 100644 --- a/src/channels.c +++ b/src/channels.c @@ -208,7 +208,7 @@ channel_class_get_name ( void *p ) static const void * channel_class_get_number ( void *p ) { - static int i; + static int64_t i; i = channel_get_number(p); return &i; } @@ -296,7 +296,8 @@ const idclass_t channel_class = { .get = channel_class_get_name, }, { - .type = PT_INT, + .type = PT_S64, + .intsplit = CHANNEL_SPLIT, .id = "number", .name = "Number", .off = offsetof(channel_t, ch_number), @@ -507,7 +508,7 @@ channel_get_name ( channel_t *ch ) return blank; } -int +int64_t channel_get_number ( channel_t *ch ) { int n; diff --git a/src/channels.h b/src/channels.h index fe0fc9cc..d75cc9ef 100644 --- a/src/channels.h +++ b/src/channels.h @@ -177,7 +177,12 @@ void channel_save(channel_t *ch); const char *channel_get_name ( channel_t *ch ); int channel_set_name ( channel_t *ch, const char *s ); -int channel_get_number ( channel_t *ch ); +#define CHANNEL_SPLIT 1000000 + +static inline uint32_t channel_get_major ( int64_t chnum ) { return chnum / CHANNEL_SPLIT; } +static inline uint32_t channel_get_minor ( int64_t chnum ) { return chnum % CHANNEL_SPLIT; } + +int64_t channel_get_number ( channel_t *ch ); const char *channel_get_icon ( channel_t *ch ); int channel_set_icon ( channel_t *ch, const char *icon ); diff --git a/src/htsp_server.c b/src/htsp_server.c index ff46aac0..05f958d8 100644 --- a/src/htsp_server.c +++ b/src/htsp_server.c @@ -550,13 +550,16 @@ htsp_build_channel(channel_t *ch, const char *method, htsp_connection_t *htsp) channel_tag_t *ct; service_t *t; epg_broadcast_t *now, *next = NULL; + int64_t chnum = channel_get_number(ch); htsmsg_t *out = htsmsg_create_map(); htsmsg_t *tags = htsmsg_create_list(); htsmsg_t *services = htsmsg_create_list(); htsmsg_add_u32(out, "channelId", channel_get_id(ch)); - htsmsg_add_u32(out, "channelNumber", channel_get_number(ch)); + htsmsg_add_u32(out, "channelNumber", channel_get_major(chnum)); + if (channel_get_minor(chnum)) + htsmsg_add_u32(out, "channelNumberMinor", channel_get_minor(chnum)); htsmsg_add_str(out, "channelName", channel_get_name(ch)); if(ch->ch_icon != NULL) { diff --git a/src/input/mpegts.h b/src/input/mpegts.h index 20e78058..285d3683 100644 --- a/src/input/mpegts.h +++ b/src/input/mpegts.h @@ -425,6 +425,7 @@ struct mpegts_service uint16_t s_dvb_service_id; uint16_t s_dvb_channel_num; + uint16_t s_dvb_channel_minor; char *s_dvb_svcname; char *s_dvb_provider; char *s_dvb_cridauth; @@ -438,7 +439,7 @@ struct mpegts_service */ int s_dvb_eit_enable; - uint16_t s_dvb_opentv_chnum; + uint64_t s_dvb_opentv_chnum; /* * Link to carrying multiplex and active adapter diff --git a/src/input/mpegts/dvb_psi.c b/src/input/mpegts/dvb_psi.c index 0a420c64..67d35c92 100644 --- a/src/input/mpegts/dvb_psi.c +++ b/src/input/mpegts/dvb_psi.c @@ -1070,11 +1070,9 @@ atsc_vct_callback tvh_str_set(&s->s_dvb_svcname, chname); save = 1; } - if (s->s_dvb_channel_num != maj) { - // TODO: ATSC channel numbering is plain weird! - // could shift the major (*100 or something) and append - // minor, but that'll probably confuse people, as will this! + if (s->s_dvb_channel_num != maj || s->s_dvb_channel_minor != min) { s->s_dvb_channel_num = maj; + s->s_dvb_channel_minor = min; save = 1; } diff --git a/src/input/mpegts/mpegts_service.c b/src/input/mpegts/mpegts_service.c index 9b2310f2..e0959257 100644 --- a/src/input/mpegts/mpegts_service.c +++ b/src/input/mpegts/mpegts_service.c @@ -20,6 +20,7 @@ #include #include "service.h" +#include "channels.h" #include "input.h" #include "settings.h" #include "dvb_charset.h" @@ -101,6 +102,13 @@ const idclass_t mpegts_service_class = .opts = PO_RDONLY, .off = offsetof(mpegts_service_t, s_dvb_channel_num), }, + { + .type = PT_U16, + .id = "lcn_minor", + .name = "Local Channel Minor", + .opts = PO_RDONLY, + .off = offsetof(mpegts_service_t, s_dvb_channel_minor), + }, { .type = PT_U16, .id = "lcn2", @@ -364,12 +372,13 @@ mpegts_service_grace_period(service_t *t) /* * Channel number */ -static int +static int64_t mpegts_service_channel_number ( service_t *s ) { - int r = ((mpegts_service_t*)s)->s_dvb_channel_num; + int r = ((mpegts_service_t*)s)->s_dvb_channel_num * CHANNEL_SPLIT + + ((mpegts_service_t*)s)->s_dvb_channel_minor; if (r <= 0) - r = ((mpegts_service_t*)s)->s_dvb_opentv_chnum; + r = ((mpegts_service_t*)s)->s_dvb_opentv_chnum * CHANNEL_SPLIT; return r; } diff --git a/src/prop.c b/src/prop.c index bb748c30..a2962ce3 100644 --- a/src/prop.c +++ b/src/prop.c @@ -133,16 +133,33 @@ prop_write_values break; } case PT_U32: { - if (htsmsg_field_get_u32(f, &u32)) - continue; + if (p->intsplit) { + char *s; + if (!(new = htsmsg_field_get_str(f))) + continue; + u32 = atol(new) * p->intsplit; + if ((s = strchr(new, '.')) != NULL) + u32 += (atol(s + 1) % p->intsplit); + } else { + if (htsmsg_field_get_u32(f, &u32)) + continue; + } PROP_UPDATE(u32, uint32_t); break; } case PT_S64: { - if (htsmsg_field_get_s64(f, &s64)) - continue; - i = s64; - PROP_UPDATE(i, int64_t); + if (p->intsplit) { + char *s; + if (!(new = htsmsg_field_get_str(f))) + continue; + s64 = atol(new) * p->intsplit; + if ((s = strchr(new, '.')) != NULL) + s64 += (atol(s + 1) % p->intsplit); + } else { + if (htsmsg_field_get_s64(f, &s64)) + continue; + } + PROP_UPDATE(s64, int64_t); break; } case PT_DBL: { @@ -230,7 +247,7 @@ prop_read_value const char *s; const void *val = obj + p->off; uint32_t u32; - char buf[16]; + char buf[24]; /* Ignore */ u32 = p->get_opts ? p->get_opts(obj) : p->opts; @@ -262,10 +279,28 @@ prop_read_value htsmsg_add_u32(m, name, *(uint16_t *)val); break; case PT_U32: - htsmsg_add_u32(m, name, *(uint32_t *)val); + if (p->intsplit) { + uint32_t maj = *(int64_t *)val / p->intsplit; + uint32_t min = *(int64_t *)val % p->intsplit; + if (min) { + snprintf(buf, sizeof(buf), "%u.%u", (unsigned int)maj, (unsigned int)min); + htsmsg_add_str(m, name, buf); + } else + htsmsg_add_s64(m, name, maj); + } else + htsmsg_add_u32(m, name, *(uint32_t *)val); break; case PT_S64: - htsmsg_add_s64(m, name, *(int64_t *)val); + if (p->intsplit) { + int64_t maj = *(int64_t *)val / p->intsplit; + int64_t min = *(int64_t *)val % p->intsplit; + if (min) { + snprintf(buf, sizeof(buf), "%lu.%lu", (unsigned long)maj, (unsigned long)min); + htsmsg_add_str(m, name, buf); + } else + htsmsg_add_s64(m, name, maj); + } else + htsmsg_add_s64(m, name, *(int64_t *)val); break; case PT_STR: if ((s = *(const char **)val)) @@ -421,6 +456,10 @@ prop_serialize_value if (pl->group) htsmsg_add_u32(m, "group", pl->group); + /* Split integer value */ + if (pl->intsplit) + htsmsg_add_u32(m, "intsplit", pl->intsplit); + /* Data */ if (obj) prop_read_value(obj, pl, m, "value", optmask); diff --git a/src/prop.h b/src/prop.h index babcb54f..42ee871d 100644 --- a/src/prop.h +++ b/src/prop.h @@ -62,10 +62,11 @@ typedef struct property { const char *id; ///< Property Key const char *name; ///< Textual description prop_type_t type; ///< Type - int islist; ///< Is a list + uint8_t islist; ///< Is a list + uint8_t group; ///< Visual group ID (like ExtJS FieldSet) size_t off; ///< Offset into object uint32_t opts; ///< Options - uint32_t group; ///< Visual group ID (like ExtJS FieldSet) + uint32_t intsplit; ///< integer/remainder boundary /* String based processing */ const void *(*get) (void *ptr); diff --git a/src/service.c b/src/service.c index 51ebd928..973c8199 100644 --- a/src/service.c +++ b/src/service.c @@ -803,7 +803,7 @@ service_destroy(service_t *t, int delconf) service_unref(t); } -static int +static int64_t service_channel_number ( service_t *s ) { return 0; @@ -1567,7 +1567,7 @@ service_get_full_channel_name ( service_t *s ) /* * Get number for service */ -int +int64_t service_get_channel_number ( service_t *s ) { if (s->s_channel_number) return s->s_channel_number(s); diff --git a/src/service.h b/src/service.h index d1419803..6707daa9 100644 --- a/src/service.h +++ b/src/service.h @@ -292,7 +292,7 @@ typedef struct service { /** * Channel info */ - int (*s_channel_number) (struct service *); + int64_t (*s_channel_number) (struct service *); const char *(*s_channel_name) (struct service *); const char *(*s_provider_name) (struct service *); @@ -554,6 +554,6 @@ void sort_elementary_streams(service_t *t); const char *service_get_channel_name (service_t *s); const char *service_get_full_channel_name (service_t *s); -int service_get_channel_number (service_t *s); +int64_t service_get_channel_number (service_t *s); #endif // SERVICE_H__ diff --git a/src/webui/statedump.c b/src/webui/statedump.c index 79dfc0fd..db74cd55 100644 --- a/src/webui/statedump.c +++ b/src/webui/statedump.c @@ -54,18 +54,27 @@ dumpchannels(htsbuf_queue_t *hq) { channel_t *ch; outputtitle(hq, 0, "Channels"); + int64_t chnum; + char chbuf[32]; CHANNEL_FOREACH(ch) { htsbuf_qprintf(hq, "%s (%d)\n", channel_get_name(ch), channel_get_id(ch)); + chnum = channel_get_number(ch); + if (channel_get_minor(chnum)) + snprintf(chbuf, sizeof(chbuf), "%u.%u", + channel_get_major(chnum), + channel_get_minor(chnum)); + else + snprintf(chbuf, sizeof(chbuf), "%u", channel_get_major(chnum)); htsbuf_qprintf(hq, " refcount = %d\n" " zombie = %d\n" - " number = %d\n" + " number = %s\n" " icon = %s\n\n", ch->ch_refcount, ch->ch_zombie, - channel_get_number(ch), + chbuf, ch->ch_icon ?: ""); } } diff --git a/src/webui/static/app/idnode.js b/src/webui/static/app/idnode.js index 175d7581..18eabf5f 100644 --- a/src/webui/static/app/idnode.js +++ b/src/webui/static/app/idnode.js @@ -122,6 +122,7 @@ tvheadend.IdNodeField = function(conf) this.hidden = conf.hidden || conf.advanced; this.password = conf.password; this.duration = conf.duration; + this.intsplit = conf.intsplit; this.group = conf.group; this.enum = conf.enum; this.store = null; @@ -490,6 +491,17 @@ tvheadend.idnode_editor_field = function(f, create) case 'u16': case 's64': case 'dbl': + if (f.intsplit) { + /* this should be improved */ + return new Ext.form.TextField({ + fieldLabel: f.caption, + name: f.id, + value: value, + disabled: d, + width: 300, + maskRe: /[0-9\.]/, + }); + } return new Ext.form.NumberField({ fieldLabel: f.caption, name: f.id,