changeset 127:8e0f7191b92e

Imported PID re-acquisition code by Toshiyuki Kawashima <tos@fa2.so-net.ne.jp>. The original patch can be obtained from http://www.castanet.homeip.net/~tos/wiki/index.php
author Yoshiki Yazawa <yaz@honeyplanet.jp>
date Mon, 12 Mar 2012 22:22:27 +0900
parents bb93a7c0ff5d
children 9e9dbb17b70f
files recpt1/recpt1.c recpt1/tssplitter_lite.c recpt1/tssplitter_lite.h
diffstat 3 files changed, 157 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/recpt1/recpt1.c	Mon Mar 05 09:46:50 2012 +0900
+++ b/recpt1/recpt1.c	Mon Mar 12 22:22:27 2012 +0900
@@ -175,7 +175,7 @@
 create_queue(size_t size)
 {
     QUEUE_T *p_queue;
-    int memsize = sizeof(QUEUE_T) + size * sizeof(BUFSZ);
+    int memsize = sizeof(QUEUE_T) + size * sizeof(BUFSZ*);
 
     p_queue = (QUEUE_T*)calloc(memsize, sizeof(char));
 
@@ -314,7 +314,7 @@
     pthread_t signal_thread = data->signal_thread;
     struct sockaddr_in *addr = NULL;
     BUFSZ *qbuf;
-    splitbuf_t splitbuf;
+    static splitbuf_t splitbuf;
     ARIB_STD_B25_BUFFER sbuf, dbuf, buf;
     int code;
     int split_select_finish = TSS_ERROR;
@@ -384,7 +384,10 @@
                 }
                 /* $BJ,N%BP>]0J30$r$U$k$$Mn$H$9(B */
                 code = split_ts(splitter, &buf, &splitbuf);
-                if(code != TSS_SUCCESS) {
+                if(code == TSS_NULL) {
+                    fprintf(stderr, "PMT reading..\n");
+                }
+                else if(code != TSS_SUCCESS) {
                     fprintf(stderr, "split_ts failed\n");
                     break;
                 }
@@ -456,7 +459,12 @@
             if(use_splitter) {
                 /* $BJ,N%BP>]0J30$r$U$k$$Mn$H$9(B */
                 code = split_ts(splitter, &buf, &splitbuf);
-                if(code != TSS_SUCCESS) {
+                if(code == TSS_NULL) {
+                    split_select_finish = TSS_ERROR;
+                    fprintf(stderr, "PMT reading..\n");
+                }
+                else if(code != TSS_SUCCESS) {
+                    fprintf(stderr, "split_ts failed\n");
                     break;
                 }
 
--- a/recpt1/tssplitter_lite.c	Mon Mar 05 09:46:50 2012 +0900
+++ b/recpt1/tssplitter_lite.c	Mon Mar 12 22:22:27 2012 +0900
@@ -33,7 +33,7 @@
 static int AnalyzePat(splitter *sp, unsigned char *buf);
 static int RecreatePat(splitter *sp, unsigned char *buf, int *pos);
 static char** AnalyzeSid(char *sid);
-static int AnalyzePmt(splitter *sp, unsigned char *buf);
+static int AnalyzePmt(splitter *sp, unsigned char *buf, unsigned char mark);
 static int GetCrc32(unsigned char *data, int len);
 static int GetPid(unsigned char *data);
 
@@ -160,6 +160,9 @@
 	sp->pmt_retain = -1;
 	sp->pmt_counter = 0;
 
+	memset(sp->section_remain, 0U, sizeof(sp->section_remain));
+	memset(sp->packet_seq, 0U, sizeof(sp->packet_seq));
+
 	return sp;
 }
 
@@ -220,6 +223,7 @@
 	int pid;
 	int result = TSS_ERROR;
 	int index;
+	int analyze_result = 0;
 
 	index = 0;
 	while(length - index - LENGTH_PACKET > 0) {
@@ -238,12 +242,13 @@
 		 * 残すべきPCR/AUDIO/VIDEO PIDを取得する */
 		if(sp->pmt_pids[pid] == 1) {
 			/* この中にはPMT毎に一度しか入らないようにしておく */
-			result = AnalyzePmt(sp, sbuf->data + index);
-			if(result != TSS_SUCCESS) {
-				return result;
+			analyze_result = AnalyzePmt(sp, sbuf->data + index, 1);
+			if(TSS_SUCCESS == analyze_result) {
+				sp->pmt_pids[pid]++;
+				sp->pmt_counter += 1;
+				*(sbuf->data + index + 1) = 0xff;
+				*(sbuf->data + index + 2) = 0xff;
 			}
-			sp->pmt_pids[pid]++;
-			sp->pmt_counter += 1;
 		}
 		/* 録画する全てのPMTについて、中にあるPCR/AUDIO/VIDEOのPIDを
 		 * 得る */
@@ -261,6 +266,37 @@
 	return(result);
 }
 
+static int RescanPID(splitter *splitter, unsigned char *buf)
+{
+	int result = TSS_NULL;
+	int i;
+
+	// clear
+	if (splitter->pmt_counter == splitter->pmt_retain) {
+	    memcpy(splitter->pids, splitter->pmt_pids, sizeof(splitter->pids));
+	    splitter->pmt_counter = 0;
+		memset(splitter->section_remain, 0U, sizeof(splitter->section_remain));
+		memset(splitter->packet_seq, 0U, sizeof(splitter->packet_seq));
+
+		fprintf(stderr, "Rescan PID \n");
+	}
+
+	if (TSS_SUCCESS == AnalyzePmt(splitter, buf, 2)) {
+	    splitter->pmt_counter += 1;
+	}
+
+ 	if (splitter->pmt_retain == splitter->pmt_counter) {
+	    result = TSS_SUCCESS;
+		for (i = 0; MAX_PID > i; i++) {
+		    if (splitter->pids[i] > 0) {
+			    splitter->pids[i] -= 1;
+		    } 
+		}
+		fprintf(stderr, "Rescan PID End\n");
+	}
+
+	return result;
+}
 /**
  * TS 分離処理
  */
@@ -274,6 +310,9 @@
 	unsigned char *sptr, *dptr;
 	int s_offset = 0;
 	int d_offset = 0;
+	int result = TSS_SUCCESS;
+	int pmts = 0;
+	int version = 0;
 
 	/* 初期化 */
 	dbuf->size = 0;
@@ -307,8 +346,31 @@
 			dbuf->size += LENGTH_PACKET;
 			break;
 		default:
+		    if(0 != splitter->pmt_pids[pid]) {
+			    //PMT
+			    if ((sptr + s_offset)[1] & 0x40) {		// PES開始インジケータ
+				    // バージョンチェック
+				    for(pmts = 0; splitter->pmt_retain > pmts; pmts++) { 
+					    if (splitter->pmt_version[pmts].pid == pid) {
+						  version = splitter->pmt_version[pmts].version;
+						  break;
+						}
+					}
+					if((version != ((sptr + s_offset)[10] & 0x3e))
+					   ||(splitter->pmt_retain != splitter->pmt_counter)) {
+					    // 再チェック
+					    result = RescanPID(splitter, sptr + s_offset);
+					} 
+				}
+				else {
+				    if (splitter->pmt_retain != splitter->pmt_counter) {
+					    // 再チェック
+					    result = RescanPID(splitter, sptr + s_offset);
+					}
+				}
+			}
 			/* pids[pid] が 1 は残すパケットなので書き込む */
-			if(1 == splitter->pids[pid]) {
+			if(0 != splitter->pids[pid]) {
 				memcpy(dptr + d_offset, sptr + s_offset, LENGTH_PACKET);
 				d_offset += LENGTH_PACKET;
 				dbuf->size += LENGTH_PACKET;
@@ -319,7 +381,7 @@
 		s_offset += LENGTH_PACKET;
 	}
 
-	return(TSS_SUCCESS);
+	return result;
 }
 
 /**
@@ -335,7 +397,7 @@
 	char** sid_list,					// [in]		出力対象サービス ID のリスト
 	unsigned char* pmt_pids,			// [out]	サービス ID に対応する PMT の PID
 	int* pmt_retain						// [out]	残すPMTの数
-)
+
 #endif
 {
 	int pos[MAX_PID];
@@ -386,6 +448,7 @@
 					*(pids+pid) = 1;
 					pos[pid] = i;
 					sid_found = TRUE;
+					sp->pmt_version[sp->pmt_retain].pid = pid;
 					sp->pmt_retain += 1;
 					sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id);
 					p++;
@@ -399,6 +462,7 @@
 						*(pids+pid) = 1;
 						pos[pid] = i;
 						sid_found = TRUE;
+						sp->pmt_version[sp->pmt_retain].pid = pid;
 						sp->pmt_retain += 1;
 						sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id);
 					}
@@ -413,6 +477,7 @@
 						*(pids+pid) = 1;
 						pos[pid] = i;
 						sid_found = TRUE;
+						sp->pmt_version[sp->pmt_retain].pid = pid;
 						sp->pmt_retain += 1;
 						sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id);
 					}
@@ -427,6 +492,7 @@
 						*(pids+pid) = 1;
 						pos[pid] = i;
 						sid_found = TRUE;
+						sp->pmt_version[sp->pmt_retain].pid = pid;
 						sp->pmt_retain += 1;
 						sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id);
 					}
@@ -441,6 +507,7 @@
 						*(pids+pid) = 1;
 						pos[pid] = i;
 						sid_found = TRUE;
+						sp->pmt_version[sp->pmt_retain].pid = pid;
 						sp->pmt_retain += 1;
 						sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id);
 					}
@@ -454,6 +521,7 @@
 					*(pids+pid) = 1;
 					pos[pid] = i;
 					sid_found = TRUE;
+					sp->pmt_version[sp->pmt_retain].pid = pid;
 					sp->pmt_retain += 1;
 					sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id);
 					break;
@@ -472,6 +540,7 @@
 				*(pids+pid) = 1;
 				pos[pid] = i;
 				sid_found = TRUE;
+				sp->pmt_version[sp->pmt_retain].pid = pid;
 				sp->pmt_retain += 1;
 				sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id);
 			}
@@ -488,7 +557,7 @@
 		/* print PMTs */
 		fprintf(stderr, "Available PMT = ");
 		for(k=0; k < sp->num_pmts; k++)
-			fprintf(stderr, "%d ", sp->avail_pmts[k]);
+			fprintf(stderr, "%d ", sp->avail_pmts[k].pid);
 		fprintf(stderr, "\n");
 #endif
 
@@ -514,7 +583,7 @@
 	unsigned char* buf,					// [in]		読み込んだバッファ
 	unsigned char** pat,				// [out]	PAT 情報(再構築後)
 	unsigned char* pids,				// [out]	出力対象 PID 情報
-	int *pos)							// [in]		取得対象 PMT のバッファ中の位置
+	int *pos							// [in]		取得対象 PMT のバッファ中の位置
 #endif
 {
 	unsigned char y[LENGTH_CRC_DATA];
@@ -580,64 +649,91 @@
  *
  * PMT を解析し、保存対象の PID を特定する
  */
-static int AnalyzePmt(splitter *sp, unsigned char *buf)
+static int AnalyzePmt(splitter *sp, unsigned char *buf, unsigned char mark)
 #if 0
 	unsigned char* buf,					// [in]		読み込んだバッファ
-	unsigned char* pids)				// [out]	出力対象 PID 情報
+	unsigned char* pids					// [out]	出力対象 PID 情報
 #endif
 {
 	unsigned char Nall;
 	unsigned char N;
 	int pcr;
 	int epid;
+	int pid;
 	int retry_count = 0;
+	int count;
+	int payload_offset;	// offset to payload
 
-	Nall = ((buf[6] & 0x0F) << 4) + buf[7];
-	if(Nall > LENGTH_PACKET)
-		Nall = LENGTH_PACKET - 8; /* xxx workaround --yaz */
+	pid = GetPid(&buf[1]);
+	if (buf[1] & 0x40) {		// PES開始インジケータ
+		sp->section_remain[pid] = ((buf[6] & 0x0F) << 8) + buf[7] + 3;	// セクションサイズ取得(ヘッダ込)
+		payload_offset = 5;
 
-	// PCR
-	pcr = GetPid(&buf[13]);
-	sp->pids[pcr] = 1;
+		for (count = 0; sp->pmt_retain > count; count++) {
+		    if (sp->pmt_version[count].pid  == pid) {
+                sp->pmt_version[count].version = buf[10] & 0x3e;
+			}
+		}
+		// PCR, 番組情報が先頭からはみ出ることはないだろう
 
-	N = ((buf[15] & 0x0F) << 4) + buf[16] + 16 + 1;
+		// PCR
+		pcr = GetPid(&buf[payload_offset + 8]);
+		sp->pids[pcr] = mark;
+
+		// ECM
+		N = ((buf[payload_offset + 10] & 0x0F) << 8) + buf[payload_offset + 11] + payload_offset + 12;	// ES情報開始点
+		int p = payload_offset + 12;
 
-	// ECM
-	int p = 17;
-	while(p < N) {
-		uint32_t ca_pid;
-		uint32_t tag;
-		uint32_t len;
+		while(p < N) {
+			uint32_t ca_pid;
+			uint32_t tag;
+			uint32_t len;
+
+			tag = buf[p];
+			len = buf[p+1];
+			p += 2;
 
-		tag = buf[p];
-		len = buf[p+1];
-		p += 2;
+			if(tag == 0x09 && len >= 4 && p+len <= N) {
+				ca_pid = ((buf[p+2] << 8) | buf[p+3]) & 0x1fff;
+				sp->pids[ca_pid] = mark;
+			}
+			p += len;
+		}
+	}
+	else {
+	    if (sp->section_remain[pid] == 0) return TSS_ERROR;								// セクション先頭が飛んでいる
+		if ((buf[3] & 0x0F) != ((sp->packet_seq[pid] + 1) & 0x0F)) return TSS_ERROR;	// パケットカウンタが飛んだ
+		payload_offset = 4;
+		N = payload_offset;
+	}
+	sp->packet_seq[pid] = buf[3] & 0x0F;				// 巡回カウンタ
 
-		if(tag == 0x09 && len >= 4 && p+len <= N) {
-			ca_pid = ((buf[p+2] << 8) | buf[p+3]) & 0x1fff;
-			sp->pids[ca_pid] = 1;
-		}
-		p += len;
-	}
+	Nall = sp->section_remain[pid];
+	if(Nall > LENGTH_PACKET - payload_offset)
+		Nall = LENGTH_PACKET - payload_offset;
 
 	// ES PID
-	while (N < Nall + 8 - 4)
+	while (N <= Nall + payload_offset - 5)
 	{
 		// ストリーム種別が 0x0D(type D)は出力対象外
 		if (0x0D != buf[N])
 		{
 			epid = GetPid(&buf[N + 1]);
 
-			sp->pids[epid] = 1;
+			sp->pids[epid] = mark;
 		}
-		N += 4 + (((buf[N + 3]) & 0x0F) << 4) + buf[N + 4] + 1;
+		N += 4 + (((buf[N + 3]) & 0x0F) << 8) + buf[N + 4] + 1;
 		retry_count++;
 		if(retry_count > Nall) {
 			return TSS_ERROR;
 		}
 	}
+	sp->section_remain[pid] -= Nall;
 
-	return TSS_SUCCESS;
+	if (sp->section_remain[pid] > 0)
+		return SECTION_CONTINUE;
+	else
+		return TSS_SUCCESS;
 }
 
 /**
--- a/recpt1/tssplitter_lite.h	Mon Mar 05 09:46:50 2012 +0900
+++ b/recpt1/tssplitter_lite.h	Mon Mar 12 22:22:27 2012 +0900
@@ -35,6 +35,13 @@
 #define TSS_NULL			(-2)
 #define LENGTH_PAT_HEADER	(12)
 #define C_CHAR_COMMA		','
+#define SECTION_CONTINUE	(1)
+
+typedef struct pmt_version {
+  int pid;
+  int version;
+  int packet;
+} pmt_version;
 
 /**
  * splitter構造体
@@ -48,7 +55,10 @@
 	int pmt_retain;
 	int pmt_counter;
 	int avail_pmts[MAX_SERVICES];
+	pmt_version pmt_version[MAX_SERVICES];
 	int num_pmts;
+	uint16_t section_remain[MAX_PID];	// セクション残りバイト数
+	uint8_t packet_seq[MAX_PID];	// 巡回カウンタ
 } splitter;
 
 /* b25 decoder would hoard up large chank */