# HG changeset patch # User Yoshiki Yazawa # Date 1331558547 -32400 # Node ID 8e0f7191b92e85e80eb9f47ec1949413535783bf # Parent bb93a7c0ff5db775001f1528fec37dd382bcd0ab Imported PID re-acquisition code by Toshiyuki Kawashima . The original patch can be obtained from http://www.castanet.homeip.net/~tos/wiki/index.php diff -r bb93a7c0ff5d -r 8e0f7191b92e recpt1/recpt1.c --- 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; } diff -r bb93a7c0ff5d -r 8e0f7191b92e recpt1/tssplitter_lite.c --- 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; } /** diff -r bb93a7c0ff5d -r 8e0f7191b92e recpt1/tssplitter_lite.h --- 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 */