Browse Source

Automatically change ECM pid if more than one is available

This allows tsdecrypt to automatically do the right thing
without having to use --ecm-pid option.

Tested on swiss viaccess encrypted streams.
Georgi Chorbadzhiyski 6 years ago
parent
commit
ac4a46b68a
3 changed files with 70 additions and 1 deletions
  1. 8
    0
      camd.c
  2. 4
    0
      data.h
  3. 58
    1
      tables.c

+ 8
- 0
camd.c View File

@@ -127,6 +127,14 @@ static int camd_recv_cw(struct ts *ts) {
127 127
 		return 0;
128 128
 
129 129
 	if (ret <= 0) {
130
+		// get_cw returned error, lets try other ecm pids, we might be lucky...
131
+		if (ts->n_ecm_pids > 1) {
132
+			ts->ecm_pid_idx++;
133
+			if (ts->ecm_pid_idx + 1 > ts->n_ecm_pids)
134
+				ts->ecm_pid_idx = 0;
135
+			ts->ecm_pid = ts->ecm_pids[ts->ecm_pid_idx];
136
+			ts_LOGf("ECM | Switching ECM pid to 0x%04x (%d) idx:%d\n", ts->ecm_pid, ts->ecm_pid, ts->ecm_pid_idx);
137
+		}
130 138
 		if (ret == -1) { // Fatal error it is better to reconnect to server.
131 139
 			ts_LOGf("ERR | No code word has been received (ret = %d)\n", ret);
132 140
 			camd_reconnect(c);

+ 4
- 0
data.h View File

@@ -233,6 +233,7 @@ struct chid {
233 233
 };
234 234
 
235 235
 #define MAX_PIDS 8192
236
+#define MAX_ECM_PIDS 16
236 237
 
237 238
 struct ts {
238 239
 	// Stream handling
@@ -251,6 +252,9 @@ struct ts {
251 252
 	uint16_t			forced_service_id;
252 253
 	uint16_t			emm_caid, emm_pid;
253 254
 	uint16_t			ecm_caid, ecm_pid;
255
+	unsigned int		n_ecm_pids;
256
+	unsigned int		ecm_pid_idx;
257
+	uint16_t			ecm_pids[MAX_ECM_PIDS];
254 258
 	uint16_t			forced_caid;
255 259
 	uint16_t			forced_emm_pid;
256 260
 	uint16_t			forced_ecm_pid;

+ 58
- 1
tables.c View File

@@ -126,6 +126,55 @@ void process_cat(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
126 126
 	}
127 127
 }
128 128
 
129
+// Copied from libtsfuncs with added logic to return more than one PID
130
+static int find_CA_descriptor(uint8_t *data, int data_len, enum CA_system req_CA_type, uint16_t *CA_id, uint16_t *CA_pid, uint16_t *CA_pids, unsigned int *n_pids) {
131
+	while (data_len >= 2) {
132
+		uint8_t tag         = data[0];
133
+		uint8_t this_length = data[1];
134
+		data     += 2;
135
+		data_len -= 2;
136
+		if (tag == 9 && this_length >= 4) {
137
+			uint16_t CA_ID = (data[0] << 8) | data[1];
138
+			uint16_t CA_PID = ((data[2] & 0x1F) << 8) | data[3];
139
+			if (ts_get_CA_sys(CA_ID) == req_CA_type) {
140
+				*CA_id = CA_ID;
141
+				*CA_pid = CA_PID;
142
+				if (*n_pids < MAX_ECM_PIDS) {
143
+					unsigned int i, exist = 0;
144
+					for (i = 0; i < MAX_ECM_PIDS; i++) {
145
+						if (CA_pids[i] == CA_PID) {
146
+							exist = 1;
147
+							break;
148
+						}
149
+					}
150
+					if (!exist) {
151
+						CA_pids[(*n_pids)++] = CA_PID;
152
+					}
153
+				}
154
+			}
155
+		}
156
+		data_len -= this_length;
157
+		data += this_length;
158
+	}
159
+	return 0;
160
+}
161
+
162
+// Copied from libtsfuncs with added logic to return more than one PID
163
+int __ts_get_ecm_info(struct ts_pmt *pmt, enum CA_system req_CA_type, uint16_t *CA_id, uint16_t *CA_pid, uint16_t *CA_pids, unsigned int *n_pids) {
164
+	int i, result = find_CA_descriptor(pmt->program_info, pmt->program_info_size, req_CA_type, CA_id, CA_pid, CA_pids, n_pids);
165
+	if (!result) {
166
+		for(i=0;i<pmt->streams_num;i++) {
167
+			struct ts_pmt_stream *stream = pmt->streams[i];
168
+			if (stream->ES_info) {
169
+				result = find_CA_descriptor(stream->ES_info, stream->ES_info_size, req_CA_type, CA_id, CA_pid, CA_pids, n_pids);
170
+				if (result)
171
+					break;
172
+			}
173
+		}
174
+	}
175
+	return result;
176
+}
177
+
129 178
 void process_pmt(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
130 179
 	int i;
131 180
 	if (!pid || pid != ts->pmt_pid)
@@ -156,11 +205,14 @@ void process_pmt(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
156 205
 	if (ts->camd.constant_codeword)
157 206
 		return;
158 207
 
208
+	ts->n_ecm_pids = 0;
159 209
 	if (ts->forced_caid) {
160 210
 		ts->ecm_caid = ts->forced_caid;
161 211
 		ts_get_ecm_info_by_caid(ts->pmt, ts->ecm_caid, &ts->ecm_pid);
212
+		ts->n_ecm_pids = 1; // TODO/FIXME: We should get the list of PIDS similar to how __ts_get_ecm_info does it
213
+		ts->ecm_pids[0] = ts->ecm_pid;
162 214
 	} else {
163
-		ts_get_ecm_info(ts->pmt, ts->req_CA_sys, &ts->ecm_caid, &ts->ecm_pid);
215
+		__ts_get_ecm_info(ts->pmt, ts->req_CA_sys, &ts->ecm_caid, &ts->ecm_pid, &ts->ecm_pids[0], &ts->n_ecm_pids);
164 216
 	}
165 217
 
166 218
 	if (ts->forced_ecm_pid)
@@ -176,6 +228,11 @@ void process_pmt(struct ts *ts, uint16_t pid, uint8_t *ts_packet) {
176 228
 				ts->ecm_pid, CA_sys, ts->forced_ecm_pid);
177 229
 			ts->ecm_pid = ts->forced_ecm_pid;
178 230
 		}
231
+		if (ts->n_ecm_pids > 1) {
232
+			for (i = 0; i < (int)ts->n_ecm_pids; i++) {
233
+				ts_LOGf("--- | ECM pid : 0x%04x (%s) idx:%d\n", ts->ecm_pids[i], CA_sys, i);
234
+			}
235
+		}
179 236
 	} else {
180 237
 		ts_LOGf("*** | ERROR: Can't detect ECM pid.\n");
181 238
 	}

Loading…
Cancel
Save