diff --git a/ffdecsa/ffdecsa.c b/ffdecsa/ffdecsa.c
index ca6d109..2ca01ff 100644
--- a/ffdecsa/ffdecsa.c
+++ b/ffdecsa/ffdecsa.c
@@ -63,8 +63,7 @@
#define PARALLEL_MODE PARALLEL_128_SSE2
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
-//#define PARALLEL_MODE PARALLEL_64_LONG
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#elif defined(__sh__) || defined(__SH4__)
#define PARALLEL_MODE PARALLEL_32_INT
@@ -75,7 +74,7 @@
#ifdef WITH_ARM_NEON
#define PARALLEL_MODE PARALLEL_128_NEON
#else
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#endif
#else
diff --git a/module-emulator-streamserver.c b/module-emulator-streamserver.c
index e32c244..3d72605 100644
--- a/module-emulator-streamserver.c
+++ b/module-emulator-streamserver.c
@@ -36,7 +36,7 @@ int32_t emu_stream_source_port = 8001;
char *emu_stream_source_auth = NULL;
int32_t emu_stream_relay_port = 17999;
int8_t emu_stream_emm_enabled = 0;
-uint32_t cluster_size = 50;
+uint32_t cluster_size = 50, suggested_cluster_size;
static uint8_t emu_stream_server_mutex_init = 0;
static pthread_mutex_t emu_stream_server_mutex;
@@ -47,6 +47,10 @@ uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS];
int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS];
pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint8_t *send_buffer[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint32_t send_buffer_length[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
+uint32_t send_buffer_offset[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
@@ -1237,19 +1241,20 @@ static void DescrambleTsPacketsCompel(emu_stream_client_data *data, uint8_t *str
}
}
-static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
+static uint16_t DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
{
- uint8_t *packetCluster[4];
- uint8_t scrambled_packets = 0, scramblingControl;
- uint32_t i, tsHeader;
- int8_t odd_even = -1, odd_even_count = 1;
+ uint8_t *packetCluster[3];
+ uint16_t retVal = 0; // return 0 if we could not descramble the packets
+
+#ifdef MODULE_RADEGAST
+ uint32_t i;
+ uint32_t tsHeader;
for (i = 0; i < bufLength; i += packetSize)
{
tsHeader = b2i(4, stream_buf + i);
- scramblingControl = (tsHeader & 0xC0) >> 6;
-#ifdef MODULE_RADEGAST
+
uint16_t pid, offset, payloadStart;
pid = (tsHeader & 0x1FFF00) >> 8;
@@ -1272,30 +1277,8 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
ParseTsData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data),
&data->ecm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEcmData, data);
}
-#endif // MODULE_RADEGAST
-
- if (scramblingControl == 0)
- {
- continue;
- }
-
- scrambled_packets++;
- scramblingControl &= 0x1;
-
- if (odd_even == -1)
- {
- odd_even = scramblingControl;
- }
-
- if (odd_even != scramblingControl)
- {
- odd_even_count++;
- odd_even = scramblingControl;
- }
}
-
- if (scrambled_packets == 0)
- return;
+#endif // MODULE_RADEGAST
SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]);
@@ -1305,14 +1288,12 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
packetCluster[1] = stream_buf + bufLength;
packetCluster[2] = NULL;
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- if (odd_even_count > 1) // odd and even packets together cannot be decrypted in one step
- {
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- }
+ retVal = decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
}
SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]);
+
+ return retVal;
}
static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path)
@@ -1393,6 +1374,181 @@ static void stream_client_disconnect(emu_stream_client_conn_data *conndata)
NULLFREE(conndata);
}
+int64_t parse_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return INVALID_PCR;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return INVALID_PCR;
+ }
+
+ if ((tsPacket[5] & 0x10)) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+ }
+
+ return INVALID_PCR;
+}
+
+int64_t parse_pcr_unchecked(const uint8_t *tsPacket) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+}
+
+int8_t has_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return 0;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return 0;
+ }
+
+ return (tsPacket[5] & 0x10);
+}
+
+uint8_t is_scrambled(const uint8_t *tsPacket) {
+ return tsPacket[3] & 0x80;
+}
+
+uint8_t has_rai_flag(const uint8_t *tsPacket) {
+ if( ( tsPacket[3] & 0x20 ) && ( tsPacket[4] > 0 ) ) {
+ return tsPacket[5] & 0x40;
+ }
+ return 0;
+}
+
+uint16_t get_pid(const uint8_t *tsPacket) {
+ return ((tsPacket[1] & 0x1f) << 8) | tsPacket[2];
+}
+
+uint64_t find_first_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=0;packetNo<numPackets;packetNo++) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint8_t *find_next_pcr_packet(uint8_t *tsPackets, uint32_t tsPacketsLen, uint8_t packetSize) {
+ uint32_t packetNo;
+ for (packetNo=0;packetNo*packetSize<tsPacketsLen;packetNo++) {
+ if (has_pcr(tsPackets+packetNo*packetSize)) {
+ return tsPackets+packetNo*packetSize;
+ }
+ }
+ return NULL;
+}
+
+uint64_t find_last_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=numPackets;packetNo-->0;) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint64_t calc_pcr_timespan(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ return find_last_pcr_value(tsPackets, numPackets, packetSize) - find_first_pcr_value(tsPackets, numPackets, packetSize);
+}
+
+uint8_t has_pusi_flag(const uint8_t *tsPacket) {
+ return tsPacket[1] & 0x40;
+}
+
+
+static void stream_client_sender(void *arg)
+{
+ uint8_t continue_sending = 1;
+ uint8_t packetSize = 188;
+ int32_t connid = ((emu_stream_client_conn_data *) arg)->connid;
+ int32_t connfd = ((emu_stream_client_conn_data *) arg)->connfd;
+
+ cs_log("Stream client %i sender started!", connid);
+ while (continue_sending) {
+ // wait until we have enough packets in send buffer
+ while (continue_sending) {
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ uint8_t *currentPacket = NULL, *descrambled_rai_packet = NULL;
+ uint64_t pcrdiff = 0;
+ uint32_t packetNo = 0;
+ for (currentPacket = send_buffer[connid]+send_buffer_offset[connid]; currentPacket<(send_buffer[connid]+send_buffer_length[connid]);currentPacket+=packetSize) {
+ if (has_rai_flag(currentPacket) && !is_scrambled(currentPacket)) {
+ descrambled_rai_packet = currentPacket;
+ break;
+ }
+ packetNo++;
+ }
+
+ if (descrambled_rai_packet != NULL) {
+ pcrdiff = calc_pcr_timespan(descrambled_rai_packet, (send_buffer[connid]+send_buffer_length[connid]-descrambled_rai_packet) / packetSize, packetSize);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ if (pcrdiff > INITIAL_BUFFER_TIME_MS*(PCR_FREQ/1000)) {
+ // printf("we have enough packets in buffer\n");
+ break;
+ } else {
+ // printf("we have a descrambled rai packet\n");
+ }
+ cs_sleepms(5); // 35 ms is a typical timespan between two PCR packets
+ }
+ cs_log("Stream client %i buffer time reached!", connid);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ while (continue_sending) {
+ uint16_t packetsToSend = (send_buffer_length[connid]-send_buffer_offset[connid]) / packetSize;
+ if (packetsToSend > 80) {
+ // limit bitrate to ~30mbit/s
+ packetsToSend = 80;
+ }
+
+ ssize_t bytesSent = send(connfd, send_buffer[connid]+send_buffer_offset[connid], packetsToSend*packetSize, 0);
+ if (bytesSent == -1) {
+ cs_log_dbg(0, "Stream client %i could not send. Stopping sender!", connid);
+ continue_sending = 0;
+ break;
+ } else if (bytesSent != packetsToSend*188) {
+ cs_log("Stream client %i sent only %d bytes", connid, bytesSent);
+ }
+
+ send_buffer_offset[connid]+=packetsToSend*188;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ cs_sleepms(5);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ }
+ cs_log("Stream client %i sender stopped!", connid);
+}
+
static void *stream_client_handler(void *arg)
{
emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg;
@@ -1410,6 +1566,15 @@ static void *stream_client_handler(void *arg)
uint16_t packetCount = 0, packetSize = 0, startOffset = 0;
uint32_t remainingDataPos, remainingDataLength, tmp_pids[4];
+ uint64_t last_pcr = INVALID_PCR;
+ uint16_t packets_since_last_pcr;
+
+ struct timeb now, postPublish = {.time = 0};
+
+ uint64_t recved_since_last_long_poll = 0;
+
+ pthread_t sender_thread;
+
struct pollfd pfd[2];
int ret;
@@ -1428,10 +1593,19 @@ static void *stream_client_handler(void *arg)
return NULL;
}
+ if (!cs_malloc(&send_buffer[conndata->connid], EMU_SEND_BUFFER_SIZE))
+ {
+ NULLFREE(http_buf);
+ NULLFREE(stream_buf);
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
if (!cs_malloc(&data, sizeof(emu_stream_client_data)))
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
stream_client_disconnect(conndata);
return NULL;
}
@@ -1441,6 +1615,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1451,6 +1626,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1485,6 +1661,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1527,6 +1704,11 @@ static void *stream_client_handler(void *arg)
streamStatus = 0;
bytesRead = 0;
+ send_buffer_length[conndata->connid] = 0;
+ send_buffer_offset[conndata->connid] = 0;
+
+ start_thread("emu stream client sender", stream_client_sender, conndata, &sender_thread, 0, 0);
+
while (!exit_oscam && clientStatus != -1 && streamStatus != -1
&& streamConnectErrorCount < 3 && streamDataErrorCount < 15)
{
@@ -1537,8 +1719,8 @@ static void *stream_client_handler(void *arg)
}
else if (emu_fixed_key_data[conndata->connid].icam_csa_used)
{
- cur_dvb_buffer_size = 188 * cluster_size;
- cur_dvb_buffer_wait = 188 * (cluster_size - 3);
+ cur_dvb_buffer_size = 188 * suggested_cluster_size;
+ cur_dvb_buffer_wait = 188 * suggested_cluster_size;
}
else
{
@@ -1551,7 +1733,15 @@ static void *stream_client_handler(void *arg)
pfd[1].fd = conndata->connfd;
pfd[1].events = POLLRDHUP | POLLHUP;
+ struct timeb preMeasure, postMeasure;
+ cs_ftimeus(&preMeasure);
ret = poll(pfd, 2, 2000);
+ cs_ftimeus(&postMeasure);
+ int64_t measured_time = comp_timebus(&postMeasure, &preMeasure);
+ if (measured_time > 2000) {
+ // printf("%7"PRIu64"\t%"PRId32"\t%"PRIu64"\n", measured_time, bytesRead, recved_since_last_long_poll);
+ recved_since_last_long_poll = 0;
+ }
if (ret < 0) // poll error
{
@@ -1571,6 +1761,7 @@ static void *stream_client_handler(void *arg)
if (pfd[0].revents & POLLIN) // new incoming data
{
streamStatus = recv(streamfd, stream_buf + bytesRead, cur_dvb_buffer_size - bytesRead, MSG_DONTWAIT);
+ recved_since_last_long_poll += streamStatus;
}
if ((pfd[0].revents & POLLHUP) || (pfd[0].revents & POLLRDHUP)) // incoming connection closed
{
@@ -1601,7 +1792,6 @@ static void *stream_client_handler(void *arg)
{
cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid);
streamDataErrorCount++;
- cs_sleepms(100);
}
}
else
@@ -1612,7 +1802,7 @@ static void *stream_client_handler(void *arg)
streamConnectErrorCount = 0;
bytesRead += streamStatus;
- if (bytesRead >= cur_dvb_buffer_wait)
+ if ((emu_fixed_key_data[data->connid].icam_csa_used && emu_fixed_key_data[data->connid].icam_csa_ks != NULL && bytesRead >= packetSize) || bytesRead >= cur_dvb_buffer_wait)
{
startOffset = 0;
@@ -1622,9 +1812,9 @@ static void *stream_client_handler(void *arg)
SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset);
}
- if (packetSize == 0)
+ if (packetSize == 0) // no ts packets found yet
{
- bytesRead = 0;
+ bytesRead = 0; // discard buffer
}
else
{
@@ -1649,7 +1839,18 @@ static void *stream_client_handler(void *arg)
}
else if (caid_is_icam(data->caid)) //ICAM
{
- DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ //struct timeb preDescramble, postDescramble;
+ //cs_ftimeus(&preDescramble);
+ packetCount = DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ cs_sleepms(1);
+ // printf("descrambled %3"PRIu16" of %3"PRIu16" packets\n", packetCount, (bytesRead - startOffset) / packetSize);
+ //cs_ftimeus(&postDescramble);
+ //printf("%7"PRId64"\n",comp_timebus(&postDescramble, &preDescramble));
+ if (packetCount == 0) {
+ // we could not descramble packets yet (probably b/c of missing cws)
+ // just copy all scrambled packets to sendbuffer
+ packetCount = ((bytesRead - startOffset) / packetSize);
+ }
}
}
else
@@ -1663,7 +1864,22 @@ static void *stream_client_handler(void *arg)
ParseTsPackets(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
}
- clientStatus = send(conndata->connfd, stream_buf + startOffset, packetCount * packetSize, 0);
+ struct timeb preMeasure, postMeasure;
+
+ // cs_ftimeus(&preMeasure);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[conndata->connid]);
+ if (send_buffer_length[conndata->connid] + packetCount * packetSize > EMU_SEND_BUFFER_SIZE) {
+ // reorganize sendbuffer
+ cs_log("reorganize send_buffer");
+ memmove(send_buffer[conndata->connid], send_buffer[conndata->connid] + send_buffer_offset[conndata->connid], send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid]);
+ send_buffer_length[conndata->connid] = send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid];
+ send_buffer_offset[conndata->connid] = 0;
+ }
+ memcpy(send_buffer[conndata->connid] + send_buffer_length[conndata->connid], stream_buf + startOffset, packetCount * packetSize);
+ send_buffer_length[conndata->connid] += packetCount * packetSize;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[conndata->connid]);
+
+ clientStatus = packetCount * packetSize;
remainingDataPos = startOffset + (packetCount * packetSize);
remainingDataLength = bytesRead - remainingDataPos;
@@ -1685,8 +1901,12 @@ static void *stream_client_handler(void *arg)
close(streamfd);
}
+ // wait for sender thread to finish
+ pthread_join(sender_thread, NULL);
+
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
for (i = 0; i < 8; i++)
{
@@ -1695,10 +1915,6 @@ static void *stream_client_handler(void *arg)
free_key_struct(data->key.pvu_csa_ks[i]);
}
}
- if (data->key.icam_csa_ks)
- {
- free_key_struct(data->key.icam_csa_ks);
- }
#ifdef MODULE_RADEGAST
icam_reset(data->connid);
#endif
@@ -1717,7 +1933,8 @@ void *stream_server(void *UNUSED(a))
emu_stream_client_conn_data *conndata;
cluster_size = get_internal_parallelism();
- cs_log("INFO: FFDecsa parallel mode = %d", cluster_size);
+ suggested_cluster_size = get_suggested_cluster_size();
+ cs_log("INFO: FFDecsa parallel mode = %d (suggested cluster size: %d packets)", cluster_size, suggested_cluster_size);
if (!emu_stream_server_mutex_init)
{
diff --git a/module-emulator-streamserver.h b/module-emulator-streamserver.h
index 5b76d0d..580e699 100644
--- a/module-emulator-streamserver.h
+++ b/module-emulator-streamserver.h
@@ -13,6 +13,15 @@
#define EMU_DVB_BUFFER_WAIT_DES 188*29
#define EMU_DVB_BUFFER_SIZE EMU_DVB_BUFFER_SIZE_CSA
+#define EMU_SEND_BUFFER_SIZE 188*204*208*2 // might implement ring buffer in future
+
+#define INVALID_PCR (uint64_t) 0xFFFFFFFFFFFFFFFF
+#define PCR_FREQ 27000000
+#define PCR_SCALE ((uint64_t)1 << 33) * 300
+
+// miliseconds of mpeg-ts to buffer
+#define INITIAL_BUFFER_TIME_MS 2500
+
typedef struct
{
uint32_t pvu_des_ks[8][2][32];
@@ -85,6 +94,8 @@ extern pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTION
extern emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
extern LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+extern pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+
void *stream_key_delayer(void *arg);
bool stream_write_cw(ECM_REQUEST *er);
diff --git a/module-emulator.c b/module-emulator.c
index 0cdb915..ce6630e 100644
--- a/module-emulator.c
+++ b/module-emulator.c
@@ -735,6 +735,7 @@ static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
{
SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL);
+ SAFE_MUTEX_INIT(&emu_send_buffer_mutex[i], NULL);
ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys");
memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data));
}
diff --git a/oscam-time.c b/oscam-time.c
index 0fceed5..7bb50b6 100644
--- a/oscam-time.c
+++ b/oscam-time.c
@@ -261,6 +261,22 @@ void add_ms_to_timeb(struct timeb *tb, int32_t ms)
}
}
+void add_us_to_timeb(struct timeb *tb, uint64_t us)
+{
+ if (us >= 1000000){
+ tb->time += us / 1000000;
+ tb->millitm += (us % 1000000);
+ }
+ else{
+ tb->millitm += us;
+ }
+ if(tb->millitm >= 1000000)
+ {
+ tb->millitm %= 1000000;
+ tb->time++;
+ }
+}
+
int64_t add_ms_to_timeb_diff(struct timeb *tb, int32_t ms)
{
struct timeb tb_now;
diff --git a/oscam-time.h b/oscam-time.h
index d04f64b..138142c 100644
--- a/oscam-time.h
+++ b/oscam-time.h
@@ -19,6 +19,7 @@ void cs_sleepus(uint32_t usec);
void add_ms_to_timespec(struct timespec *timeout, int32_t msec);
void add_ms_to_timeb(struct timeb *tb, int32_t ms);
+void add_us_to_timeb(struct timeb *tb, uint64_t us);
int64_t add_ms_to_timeb_diff(struct timeb *tb, int32_t ms);
time_t cs_walltime(struct timeb *tp);
diff --git a/ffdecsa/ffdecsa.c b/ffdecsa/ffdecsa.c
index ca6d109..2ca01ff 100644
--- a/ffdecsa/ffdecsa.c
+++ b/ffdecsa/ffdecsa.c
@@ -63,8 +63,7 @@
#define PARALLEL_MODE PARALLEL_128_SSE2
#elif defined(__mips__) || defined(__mips) || defined(__MIPS__)
-//#define PARALLEL_MODE PARALLEL_64_LONG
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#elif defined(__sh__) || defined(__SH4__)
#define PARALLEL_MODE PARALLEL_32_INT
@@ -75,7 +74,7 @@
#ifdef WITH_ARM_NEON
#define PARALLEL_MODE PARALLEL_128_NEON
#else
-#define PARALLEL_MODE PARALLEL_32_INT
+#define PARALLEL_MODE PARALLEL_64_LONG
#endif
#else
diff --git a/module-emulator-streamserver.c b/module-emulator-streamserver.c
index e32c244..70851cc 100644
--- a/module-emulator-streamserver.c
+++ b/module-emulator-streamserver.c
@@ -36,7 +36,7 @@ int32_t emu_stream_source_port = 8001;
char *emu_stream_source_auth = NULL;
int32_t emu_stream_relay_port = 17999;
int8_t emu_stream_emm_enabled = 0;
-uint32_t cluster_size = 50;
+uint32_t cluster_size = 50, suggested_cluster_size;
static uint8_t emu_stream_server_mutex_init = 0;
static pthread_mutex_t emu_stream_server_mutex;
@@ -47,6 +47,10 @@ uint16_t emu_stream_cur_srvid[EMU_STREAM_SERVER_MAX_CONNECTIONS];
int8_t stream_server_has_ecm[EMU_STREAM_SERVER_MAX_CONNECTIONS];
pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint8_t *send_buffer[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+uint32_t send_buffer_length[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
+uint32_t send_buffer_offset[EMU_STREAM_SERVER_MAX_CONNECTIONS] = {0};
emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
@@ -1237,19 +1241,20 @@ static void DescrambleTsPacketsCompel(emu_stream_client_data *data, uint8_t *str
}
}
-static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
+static uint16_t DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *stream_buf, uint32_t bufLength, uint16_t packetSize)
{
- uint8_t *packetCluster[4];
- uint8_t scrambled_packets = 0, scramblingControl;
- uint32_t i, tsHeader;
- int8_t odd_even = -1, odd_even_count = 1;
+ uint8_t *packetCluster[3];
+ uint16_t retVal = bufLength / packetSize;
+
+#ifdef MODULE_RADEGAST
+ uint32_t i;
+ uint32_t tsHeader;
for (i = 0; i < bufLength; i += packetSize)
{
tsHeader = b2i(4, stream_buf + i);
- scramblingControl = (tsHeader & 0xC0) >> 6;
-#ifdef MODULE_RADEGAST
+
uint16_t pid, offset, payloadStart;
pid = (tsHeader & 0x1FFF00) >> 8;
@@ -1272,30 +1277,8 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
ParseTsData(0x80, 0xFE, 3, &data->have_ecm_data, data->ecm_data, sizeof(data->ecm_data),
&data->ecm_data_pos, payloadStart, stream_buf + i + offset, packetSize - offset, ParseEcmData, data);
}
-#endif // MODULE_RADEGAST
-
- if (scramblingControl == 0)
- {
- continue;
- }
-
- scrambled_packets++;
- scramblingControl &= 0x1;
-
- if (odd_even == -1)
- {
- odd_even = scramblingControl;
- }
-
- if (odd_even != scramblingControl)
- {
- odd_even_count++;
- odd_even = scramblingControl;
- }
}
-
- if (scrambled_packets == 0)
- return;
+#endif // MODULE_RADEGAST
SAFE_MUTEX_LOCK(&emu_fixed_key_data_mutex[data->connid]);
@@ -1305,14 +1288,12 @@ static void DescrambleTsPacketsICam(emu_stream_client_data *data, uint8_t *strea
packetCluster[1] = stream_buf + bufLength;
packetCluster[2] = NULL;
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- if (odd_even_count > 1) // odd and even packets together cannot be decrypted in one step
- {
- decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
- }
+ retVal = decrypt_packets(emu_fixed_key_data[data->connid].icam_csa_ks, packetCluster);
}
SAFE_MUTEX_UNLOCK(&emu_fixed_key_data_mutex[data->connid]);
+
+ return retVal;
}
static int32_t connect_to_stream(char *http_buf, int32_t http_buf_len, char *stream_path)
@@ -1393,6 +1374,179 @@ static void stream_client_disconnect(emu_stream_client_conn_data *conndata)
NULLFREE(conndata);
}
+int64_t parse_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return INVALID_PCR;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return INVALID_PCR;
+ }
+
+ if ((tsPacket[5] & 0x10)) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+ }
+
+ return INVALID_PCR;
+}
+
+int64_t parse_pcr_unchecked(const uint8_t *tsPacket) {
+ uint16_t extension = 0;
+ uint64_t base = 0;
+
+ base |= (uint64_t)(tsPacket[6])<<25;
+ base |= (uint64_t)(tsPacket[7])<<(25-8);
+ base |= (uint64_t)(tsPacket[8])<<(25-8-8);
+ base |= (uint64_t)(tsPacket[9])<<(25-8-8-8);
+ base |= (uint16_t)(tsPacket[10] & 128)>>7;
+ extension |= tsPacket[11];
+ extension |= (uint16_t)(tsPacket[10] & 0x01)<<8;
+
+ return base*300 + extension;
+}
+
+int8_t has_pcr(const uint8_t *tsPacket) {
+ if (tsPacket[0] != 0x47) {
+ return 0;
+ }
+
+ if (!(tsPacket[3] & 0x20)) {
+ return 0;
+ }
+
+ return (tsPacket[5] & 0x10);
+}
+
+uint8_t is_scrambled(const uint8_t *tsPacket) {
+ return tsPacket[3] & 0x80;
+}
+
+uint8_t has_rai_flag(const uint8_t *tsPacket) {
+ if( ( tsPacket[3] & 0x20 ) && ( tsPacket[4] > 0 ) ) {
+ return tsPacket[5] & 0x40;
+ }
+ return 0;
+}
+
+uint16_t get_pid(const uint8_t *tsPacket) {
+ return ((tsPacket[1] & 0x1f) << 8) | tsPacket[2];
+}
+
+uint64_t find_first_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=0;packetNo<numPackets;packetNo++) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint8_t *find_next_pcr_packet(uint8_t *tsPackets, uint32_t tsPacketsLen, uint8_t packetSize) {
+ uint32_t packetNo;
+ for (packetNo=0;packetNo*packetSize<tsPacketsLen;packetNo++) {
+ if (has_pcr(tsPackets+packetNo*packetSize)) {
+ return tsPackets+packetNo*packetSize;
+ }
+ }
+ return NULL;
+}
+
+uint64_t find_last_pcr_value(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ uint32_t packetNo;
+ uint64_t pcr = INVALID_PCR;
+ for (packetNo=numPackets;packetNo-->0;) {
+ pcr = parse_pcr(tsPackets+packetNo*packetSize);
+ if (pcr != INVALID_PCR) {
+ return pcr;
+ }
+ }
+ return INVALID_PCR;
+}
+
+uint64_t calc_pcr_timespan(const uint8_t *tsPackets, const uint32_t numPackets, const uint8_t packetSize) {
+ return find_last_pcr_value(tsPackets, numPackets, packetSize) - find_first_pcr_value(tsPackets, numPackets, packetSize);
+}
+
+uint8_t has_pusi_flag(const uint8_t *tsPacket) {
+ return tsPacket[1] & 0x40;
+}
+
+
+static void stream_client_sender(void *arg)
+{
+ uint8_t continue_sending = 1;
+ uint8_t packetSize = 188;
+ int32_t connid = ((emu_stream_client_conn_data *) arg)->connid;
+ int32_t connfd = ((emu_stream_client_conn_data *) arg)->connfd;
+
+ cs_log("Stream client %i sender started!", connid);
+ while (continue_sending) {
+ // wait until we have enough packets in send buffer
+ while (continue_sending) {
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ uint8_t *currentPacket = NULL, *descrambled_rai_packet = NULL;
+ uint64_t pcrdiff = 0;
+ uint32_t packetNo = 0;
+ for (currentPacket = send_buffer[connid]+send_buffer_offset[connid]; currentPacket<(send_buffer[connid]+send_buffer_length[connid]);currentPacket+=packetSize) {
+ if (has_rai_flag(currentPacket) && !is_scrambled(currentPacket)) {
+ descrambled_rai_packet = currentPacket;
+ break;
+ }
+ packetNo++;
+ }
+
+ if (descrambled_rai_packet != NULL) {
+ pcrdiff = calc_pcr_timespan(descrambled_rai_packet, (send_buffer[connid]+send_buffer_length[connid]-descrambled_rai_packet) / packetSize, packetSize);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ if (pcrdiff > INITIAL_BUFFER_TIME_MS*(PCR_FREQ/1000)) {
+ break;
+ } else {
+ }
+ cs_sleepms(35); // 35 ms is a typical timespan between two PCR packets
+ }
+ cs_log("Stream client %i buffer time reached!", connid);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ while (continue_sending) {
+ uint16_t packetsToSend = (send_buffer_length[connid]-send_buffer_offset[connid]) / packetSize;
+ if (packetsToSend > 80) {
+ // limit bitrate to ~30mbit/s
+ packetsToSend = 80;
+ }
+
+ ssize_t bytesSent = send(connfd, send_buffer[connid]+send_buffer_offset[connid], packetsToSend*packetSize, 0);
+ if (bytesSent == -1) {
+ cs_log_dbg(0, "Stream client %i could not send. Stopping sender!", connid);
+ continue_sending = 0;
+ break;
+ } else if (bytesSent != packetsToSend*188) {
+ cs_log("Stream client %i sent only %d bytes", connid, bytesSent);
+ }
+
+ send_buffer_offset[connid]+=packetsToSend*188;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ cs_sleepms(5);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[connid]);
+ }
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[connid]);
+ }
+ cs_log("Stream client %i sender stopped!", connid);
+}
+
static void *stream_client_handler(void *arg)
{
emu_stream_client_conn_data *conndata = (emu_stream_client_conn_data *)arg;
@@ -1410,6 +1564,15 @@ static void *stream_client_handler(void *arg)
uint16_t packetCount = 0, packetSize = 0, startOffset = 0;
uint32_t remainingDataPos, remainingDataLength, tmp_pids[4];
+ uint64_t last_pcr = INVALID_PCR;
+ uint16_t packets_since_last_pcr;
+
+ struct timeb now, postPublish = {.time = 0};
+
+ uint64_t recved_since_last_long_poll = 0;
+
+ pthread_t sender_thread;
+
struct pollfd pfd[2];
int ret;
@@ -1428,10 +1591,19 @@ static void *stream_client_handler(void *arg)
return NULL;
}
+ if (!cs_malloc(&send_buffer[conndata->connid], EMU_SEND_BUFFER_SIZE))
+ {
+ NULLFREE(http_buf);
+ NULLFREE(stream_buf);
+ stream_client_disconnect(conndata);
+ return NULL;
+ }
+
if (!cs_malloc(&data, sizeof(emu_stream_client_data)))
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
stream_client_disconnect(conndata);
return NULL;
}
@@ -1441,6 +1613,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1451,6 +1624,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1485,6 +1659,7 @@ static void *stream_client_handler(void *arg)
{
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
NULLFREE(data);
stream_client_disconnect(conndata);
return NULL;
@@ -1527,6 +1702,11 @@ static void *stream_client_handler(void *arg)
streamStatus = 0;
bytesRead = 0;
+ send_buffer_length[conndata->connid] = 0;
+ send_buffer_offset[conndata->connid] = 0;
+
+ start_thread("emu stream client sender", stream_client_sender, conndata, &sender_thread, 0, 0);
+
while (!exit_oscam && clientStatus != -1 && streamStatus != -1
&& streamConnectErrorCount < 3 && streamDataErrorCount < 15)
{
@@ -1537,8 +1717,8 @@ static void *stream_client_handler(void *arg)
}
else if (emu_fixed_key_data[conndata->connid].icam_csa_used)
{
- cur_dvb_buffer_size = 188 * cluster_size;
- cur_dvb_buffer_wait = 188 * (cluster_size - 3);
+ cur_dvb_buffer_size = 188 * suggested_cluster_size;
+ cur_dvb_buffer_wait = 188 * suggested_cluster_size;
}
else
{
@@ -1546,12 +1726,15 @@ static void *stream_client_handler(void *arg)
cur_dvb_buffer_wait = EMU_DVB_BUFFER_WAIT_DES;
}
+ uint8_t packets_left_in_buffer = (packetSize > 0) ? bytesRead/packetSize:0;
+ uint8_t descrambling = data->have_pat_data == 1 && data->have_pmt_data == 1;
+
pfd[0].fd = streamfd;
pfd[0].events = POLLIN | POLLRDHUP | POLLHUP;
pfd[1].fd = conndata->connfd;
pfd[1].events = POLLRDHUP | POLLHUP;
- ret = poll(pfd, 2, 2000);
+ ret = poll(pfd, 2, (packets_left_in_buffer > 0 && descrambling) ? 5:2000);
if (ret < 0) // poll error
{
@@ -1562,9 +1745,14 @@ static void *stream_client_handler(void *arg)
}
else if (ret == 0) // timeout
{
- cs_log("WARNING: stream client %i no data from stream source", conndata->connid);
- streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close
- continue;
+ if (packets_left_in_buffer > 0 && descrambling) {
+ // was fast timeout
+ streamStatus = 0; // act like we received 0 new bytes
+ } else {
+ cs_log("WARNING: stream client %i no data from stream source", conndata->connid);
+ streamDataErrorCount++; // 2 sec timeout * 15 = 30 seconds no data -> close
+ continue;
+ }
}
else
{
@@ -1601,7 +1789,6 @@ static void *stream_client_handler(void *arg)
{
cs_log_dbg(0, "WARNING: stream client %i non-full buffer from stream source", conndata->connid);
streamDataErrorCount++;
- cs_sleepms(100);
}
}
else
@@ -1612,7 +1799,7 @@ static void *stream_client_handler(void *arg)
streamConnectErrorCount = 0;
bytesRead += streamStatus;
- if (bytesRead >= cur_dvb_buffer_wait)
+ if (bytesRead >= cur_dvb_buffer_wait || (packets_left_in_buffer > 0 && descrambling))
{
startOffset = 0;
@@ -1622,9 +1809,9 @@ static void *stream_client_handler(void *arg)
SearchTsPackets(stream_buf, bytesRead, &packetSize, &startOffset);
}
- if (packetSize == 0)
+ if (packetSize == 0) // no ts packets found yet
{
- bytesRead = 0;
+ bytesRead = 0; // discard buffer
}
else
{
@@ -1649,7 +1836,8 @@ static void *stream_client_handler(void *arg)
}
else if (caid_is_icam(data->caid)) //ICAM
{
- DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ packetCount = DescrambleTsPacketsICam(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
+ cs_sleepus(1500);
}
}
else
@@ -1663,7 +1851,18 @@ static void *stream_client_handler(void *arg)
ParseTsPackets(data, stream_buf + startOffset, packetCount * packetSize, packetSize);
}
- clientStatus = send(conndata->connfd, stream_buf + startOffset, packetCount * packetSize, 0);
+ SAFE_MUTEX_LOCK(&emu_send_buffer_mutex[conndata->connid]);
+ if (send_buffer_length[conndata->connid] + packetCount * packetSize > EMU_SEND_BUFFER_SIZE) {
+ // reorganize sendbuffer
+ memmove(send_buffer[conndata->connid], send_buffer[conndata->connid] + send_buffer_offset[conndata->connid], send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid]);
+ send_buffer_length[conndata->connid] = send_buffer_length[conndata->connid] - send_buffer_offset[conndata->connid];
+ send_buffer_offset[conndata->connid] = 0;
+ }
+ memcpy(send_buffer[conndata->connid] + send_buffer_length[conndata->connid], stream_buf + startOffset, packetCount * packetSize);
+ send_buffer_length[conndata->connid] += packetCount * packetSize;
+ SAFE_MUTEX_UNLOCK(&emu_send_buffer_mutex[conndata->connid]);
+
+ clientStatus = packetCount * packetSize;
remainingDataPos = startOffset + (packetCount * packetSize);
remainingDataLength = bytesRead - remainingDataPos;
@@ -1685,8 +1884,12 @@ static void *stream_client_handler(void *arg)
close(streamfd);
}
+ // wait for sender thread to finish
+ pthread_join(sender_thread, NULL);
+
NULLFREE(http_buf);
NULLFREE(stream_buf);
+ NULLFREE(send_buffer[conndata->connid]);
for (i = 0; i < 8; i++)
{
@@ -1695,10 +1898,6 @@ static void *stream_client_handler(void *arg)
free_key_struct(data->key.pvu_csa_ks[i]);
}
}
- if (data->key.icam_csa_ks)
- {
- free_key_struct(data->key.icam_csa_ks);
- }
#ifdef MODULE_RADEGAST
icam_reset(data->connid);
#endif
@@ -1717,7 +1916,8 @@ void *stream_server(void *UNUSED(a))
emu_stream_client_conn_data *conndata;
cluster_size = get_internal_parallelism();
- cs_log("INFO: FFDecsa parallel mode = %d", cluster_size);
+ suggested_cluster_size = get_suggested_cluster_size();
+ cs_log("INFO: FFDecsa parallel mode = %d (suggested cluster size: %d packets)", cluster_size, suggested_cluster_size);
if (!emu_stream_server_mutex_init)
{
diff --git a/module-emulator-streamserver.h b/module-emulator-streamserver.h
index 5b76d0d..580e699 100644
--- a/module-emulator-streamserver.h
+++ b/module-emulator-streamserver.h
@@ -13,6 +13,15 @@
#define EMU_DVB_BUFFER_WAIT_DES 188*29
#define EMU_DVB_BUFFER_SIZE EMU_DVB_BUFFER_SIZE_CSA
+#define EMU_SEND_BUFFER_SIZE 188*204*208*2 // might implement ring buffer in future
+
+#define INVALID_PCR (uint64_t) 0xFFFFFFFFFFFFFFFF
+#define PCR_FREQ 27000000
+#define PCR_SCALE ((uint64_t)1 << 33) * 300
+
+// miliseconds of mpeg-ts to buffer
+#define INITIAL_BUFFER_TIME_MS 2500
+
typedef struct
{
uint32_t pvu_des_ks[8][2][32];
@@ -85,6 +94,8 @@ extern pthread_mutex_t emu_fixed_key_data_mutex[EMU_STREAM_SERVER_MAX_CONNECTION
extern emu_stream_client_key_data emu_fixed_key_data[EMU_STREAM_SERVER_MAX_CONNECTIONS];
extern LLIST *ll_emu_stream_delayed_keys[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+extern pthread_mutex_t emu_send_buffer_mutex[EMU_STREAM_SERVER_MAX_CONNECTIONS];
+
void *stream_key_delayer(void *arg);
bool stream_write_cw(ECM_REQUEST *er);
diff --git a/module-emulator.c b/module-emulator.c
index 0cdb915..ce6630e 100644
--- a/module-emulator.c
+++ b/module-emulator.c
@@ -735,6 +735,7 @@ static int32_t emu_reader_init(struct s_reader *UNUSED(reader))
for (i = 0; i < EMU_STREAM_SERVER_MAX_CONNECTIONS; i++)
{
SAFE_MUTEX_INIT(&emu_fixed_key_data_mutex[i], NULL);
+ SAFE_MUTEX_INIT(&emu_send_buffer_mutex[i], NULL);
ll_emu_stream_delayed_keys[i] = ll_create("ll_emu_stream_delayed_keys");
memset(&emu_fixed_key_data[i], 0, sizeof(emu_stream_client_key_data));
}
svn export https://svn.streamboard.tv/oscam/trunk oscam
pushd oscam || cd oscam
patch -i ../oscam-emu.patch -p0
patch -i ../oscam_emu_icam_dvbapi_radegast_v9.patch.txt -p1
patch -i ../buffer.patch -p1
popd || cd ..
Die für 11725 gabs hier nicht glaube nicht. 11724 war die letzte soweit ich weiss. Und die für 11725, die habe ich auch vom streamboard.Bash:svn export https://svn.streamboard.tv/oscam/trunk oscam pushd oscam || cd oscam patch -i ../oscam-emu.patch -p0 patch -i ../oscam_emu_icam_dvbapi_radegast_v9.patch.txt -p 1 patch -i ../buffer.patch -p1 popd || cd ..
weiß gerade nur nicht, wo ich den oscam-emu.patch für 11725 bezogen habe. ich meine das war im streamboard
patch -p0 < oscam-emu.patch
patch -p1 < oscam_emu_icam_dvbapi_radegast_v9.patch
patch -p1 < buffer.patch
Wir verwenden Cookies und ähnliche Technologien für folgende Zwecke:
Akzeptieren Sie Cookies und diese Technologien?
Wir verwenden Cookies und ähnliche Technologien für folgende Zwecke:
Akzeptieren Sie Cookies und diese Technologien?