changeset 122:4009737ea899

add es output arg: add start_time arg:
author Naoya OYAMA <naoya.oyama@gmail.com>
date Wed, 05 May 2010 20:43:43 +0900
parents e915d31c5bd9
children 215a51fa3df3
files recpt1/configure.ac recpt1/recpt1.c recpt1/tssplitter_lite.c recpt1/tssplitter_lite.h
diffstat 4 files changed, 539 insertions(+), 301 deletions(-) [+]
line wrap: on
line diff
--- a/recpt1/configure.ac	Thu Apr 29 02:02:42 2010 +0900
+++ b/recpt1/configure.ac	Wed May 05 20:43:43 2010 +0900
@@ -18,7 +18,6 @@
 # Checks for libraries.
 AC_CHECK_LIB([m], [log10])
 AC_CHECK_LIB([pthread], [pthread_kill])
-AC_CHECK_LIB([rt], [log10])
 
 AC_CONFIG_FILES([Makefile])
 AC_OUTPUT
--- a/recpt1/recpt1.c	Thu Apr 29 02:02:42 2010 +0900
+++ b/recpt1/recpt1.c	Wed May 05 20:43:43 2010 +0900
@@ -1,4 +1,5 @@
 /* -*- tab-width: 4; indent-tabs-mode: nil -*- */
+/* vim: set ts=4 sts=4 sw=4 expandtab number : */
 #include <stdio.h>
 #include <fcntl.h>
 #include <sys/types.h>
@@ -336,8 +337,8 @@
         if(use_b25) {
             code = b25_decode(dec, &sbuf, &dbuf);
             if(code < 0) {
-                fprintf(stderr, "b25_decode failed. fall back to encrypted recording.\n");
-                use_b25 = FALSE; /* local flag */
+                fprintf(stderr, "b25_decode failed (code=%d). fall back to encrypted recording.\n", code);
+                use_b25 = FALSE;
             }
             else
                 buf = dbuf;
@@ -361,6 +362,12 @@
                         /* $BJ,N%BP>](BPID$B$,40A4$KCj=P$G$-$k$^$G=PNO$7$J$$(B
                          * 1$BICDxEYM>M5$r8+$k$H$$$$$+$b(B
                          */
+                        time_t cur_time;
+                        time(&cur_time);
+                        if(cur_time - data->start_time > 4) {
+                            use_splitter = FALSE;
+                            goto fin;
+                        }
                         break;
                     }
                 }
@@ -480,9 +487,9 @@
 show_usage(char *cmd)
 {
 #ifdef HAVE_LIBARIB25
-    fprintf(stderr, "Usage: \n%s [--b25 [--round N] [--strip] [--EMM]] [--udp [--addr hostname --port portnumber]] [--device devicefile] [--lnb voltage] [--sid SID1,SID2] channel [--es filename_suffix] rectime destfile\n", cmd);
+    fprintf(stderr, "Usage: \n%s [--b25 [--round N] [--strip] [--EMM]] [--udp [--addr hostname --port portnumber]] [--device devicefile] [--lnb voltage] [--sid SID1,SID2] [--es filename_suffix] [--start_time YYYYMMDDHHMISS] channel rectime destfile\n", cmd);
 #else
-    fprintf(stderr, "Usage: \n%s [--strip] [--EMM]] [--udp [--addr hostname --port portnumber]] [--device devicefile] [--lnb voltage] [--sid SID1,SID2] [--es filename_suffix] channel rectime destfile\n", cmd);
+    fprintf(stderr, "Usage: \n%s [--strip] [--EMM]] [--udp [--addr hostname --port portnumber]] [--device devicefile] [--lnb voltage] [--sid SID1,SID2] [--es filename_suffix] [--start_time YYYYMMDDHHMISS] channel rectime destfile\n", cmd);
 #endif
     fprintf(stderr, "\n");
     fprintf(stderr, "Remarks:\n");
@@ -507,6 +514,7 @@
     fprintf(stderr, "--lnb voltage:       Specify LNB voltage (0, 11, 15)\n");
     fprintf(stderr, "--sid SID1,SID2,...: Specify SID number in CSV format (101,102,...)\n");
     fprintf(stderr, "  --es filename:     Specify ES out filename prefix\n");
+    fprintf(stderr, "  --start_time YYYYMMDDHHMISS: Specify record start datetime\n");
     fprintf(stderr, "--help:              Show this help\n");
     fprintf(stderr, "--version:           Show version\n");
     fprintf(stderr, "--list:              Show channel list\n");
@@ -896,6 +904,7 @@
         { "SID",       1, NULL, 'i'},
         { "es",       1, NULL, 'e'},
         { "ES",       1, NULL, 'e'},
+        { "start_time",       1, NULL, 'y'},
         {0, 0, NULL, 0} /* terminate */
     };
 
@@ -912,6 +921,7 @@
     char *voltage[] = {"0V", "11V", "15V"};
     char *sid_list = NULL;
     char *es_name_prefix = NULL;
+    char *start_time = NULL;
 
     while((result = getopt_long(argc, argv, "br:smn:ua:p:d:hvli:",
                                 long_options, &option_index)) != -1) {
@@ -992,6 +1002,9 @@
         case 'e':
             es_name_prefix = optarg;
             break;
+        case 'y':
+            start_time = optarg;
+            break;
         }
     }
 
@@ -1049,15 +1062,13 @@
         if(!dec) {
             fprintf(stderr, "Cannot start b25 decoder\n");
             fprintf(stderr, "Fall back to encrypted recording\n");
-            use_b25 = 0;
+            use_b25 = FALSE;
         }
     }
     /* initialize splitter */
-    if(use_splitter)
-    {
-        splitter = split_startup(sid_list, es_name_prefix);
-        if ( splitter->sid_list == NULL )
-        {
+    if(use_splitter) {
+        splitter = split_startup(sid_list, es_name_prefix, start_time);
+        if(splitter->sid_list == NULL) {
             fprintf(stderr, "Cannot start TS splitter\n");
             return 1;
         }
--- a/recpt1/tssplitter_lite.c	Thu Apr 29 02:02:42 2010 +0900
+++ b/recpt1/tssplitter_lite.c	Wed May 05 20:43:43 2010 +0900
@@ -48,6 +48,9 @@
 #define AV_RB16(x)  ((((const uint8_t*)(x))[0] << 8) | ((const uint8_t*)(x))[1])
 #endif
 #define MAX_SERVICE_ID ( 0xffff )
+#define LIST_DECIMAL "0123456789"
+#define TSS_STREAM_TYPE_AUDIO (1)
+#define TSS_STREAM_TYPE_VIDEO (2)
 
 /* prototypes */
 static int ReadTs(splitter *sp, ARIB_STD_B25_BUFFER *sbuf);
@@ -58,23 +61,23 @@
 static int GetCrc32(unsigned char *data, int len);
 static int GetPid(unsigned char *data);
 static int parse_tot( const unsigned char* packet, time_t *t );
-void dump_packet( const uint8_t *packet );
+//void dump_packet( const uint8_t *packet );
 static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, const uint8_t *packet);
-static int DemuxTs(const uint8_t *packet, splitter *sp, const int pid, int *random_access);
-static int pes2es(splitpesbuf_t *pesbuf, splitesbuf_t *esbuf, const int pid, int random_access_indicator);
+static int DemuxTs(const uint8_t *packet, splitter *sp, const int pid);
+//static int pes2es(splitpesbuf_t *pesbuf, splitesbuf_t *esbuf, const int pid, int random_access_indicator);
+static int pes2es(splitpesbuf_t *pesbuf, splitesbuf_t *esbuf, const int pid);
 static int64_t get_pts(const uint8_t *p);
-void search_mpeg_system_header(const uint8_t *p);
-int esbuf_write(splitesbuf_t *esbuf);
-//void forward_stc(timespec *stc, timespec offset);
+//void search_mpeg_system_header(const uint8_t *p);
+static int esbuf_write(splitesbuf_t *esbuf);
 static int pesbuf_packet_start_code_prefix(splitpesbuf_t *pesbuf);
 static int pesbuf_empty(splitpesbuf_t *pesbuf);
 void pesbuf_clear(splitpesbuf_t *pesbuf);
 static int pesbuf_add(splitpesbuf_t *pesbuf, const uint8_t *data, int len);
 static int esbuf_empty(splitesbuf_t *esbuf);
-void esbuf_clear(splitesbuf_t *esbuf);
+void esbuf_clear(splitesbuf_t *esbuf, uint64_t pts, uint64_t dts);
 static int esbuf_add(splitesbuf_t *esbuf, const uint8_t *data, int len);
 static int get_pmt_version(const uint8_t *p);
-static int esbuf_adts_start_code_prefix(splitesbuf_t *esbuf, int offset);
+static int next_adts_start_code(splitesbuf_t *esbuf, int offset);
 static int is_video_stream(const int pid, splitesbuf_t *esbuf);
 static int is_audio_stream(const int pid, splitesbuf_t *esbuf);
 static int AnalyzeAdifHeader(splitesbuf_t *esbuf);
@@ -92,10 +95,11 @@
 static int get_adif_aac_frame_length(uint8_t *p);
 static int get_adts_buffer_fullness(uint8_t *p);
 static int get_adts_no_raw_data_blocks_in_frame(uint8_t *p);
-static int search_pmt_program(splitter *sp, int pid);
+//static int search_pmt_program(splitter *sp, int pid);
 static int search_gop_start_code(splitesbuf_t *esbuf);
-//static int creat_filename(char *base, char *filename, int sid, int epid, int av_flag ,splitesbuf_t *esbuf);
-static int creat_filename(splitter *sp, int sid, int pid, int av_flag);
+static int creat_es_file(splitter *sp, int sid, int pid, int av_flag);
+static time_t cue2time(char *yyyymmddhhmiss);
+static int search_pcr_pid(splitter *sp, int pid);
 
 /**
  * サービスID解析
@@ -196,7 +200,8 @@
  */
 splitter* split_startup(
 	char *sid,		// [in]		サービスID(引数で指定した文字列)
-	char *filename	// [in]		出力ESファイル名(引数で指定したファイル名)
+	char *filename,	// [in]		出力ESファイル名(引数で指定したファイル名)
+	char *arg_cue	// [in]		録画開始時刻(引数で指定した文字列 YYYYMMDDHHMISS)
 )
 {
 	splitter* sp;
@@ -215,6 +220,9 @@
 	}
 	memset(sp->pids, 0, sizeof(sp->pids));
 	memset(sp->pmt_pids, 0, sizeof(sp->pmt_pids));
+	memset(sp->cat_pids, 0, sizeof(sp->cat_pids));
+	memset(sp->pcr_pids, 0, sizeof(sp->pcr_pids));
+	memset(sp->pcr, 0, sizeof(sp->pcr));
 
 	sp->sid_list	= NULL;
 	sp->pat			= NULL;
@@ -227,26 +235,28 @@
 	sp->pat_count	= 0xFF;
 	sp->pmt_retain = -1;
 	sp->pmt_counter = 0;
-//	sp->STC_timespec.tv_sec = 0;
-//	sp->STC_timespec.tv_nsec = 0;
-//	sp->tot_offset.tv_sec = 0;
-//	sp->tot_offset.tv_nsec = 0;
-	sp->cue_time = -1;
-	sp->stc = 0;
-	sp->status = 1;
+	sp->time_cue = 0;
+	sp->time_tot = 0;
+	sp->pcr_nb = 0;
 	memset(sp->esbuf, 0, sizeof(splitesbuf_t *)*MAX_PID);
 	memset(sp->pesbuf, 0, sizeof(splitpesbuf_t *)*MAX_PID);
 	memset(sp->program, 0, sizeof(program_t *)*MAX_SERVICE_ID);
 	for ( i=0; i < MAX_PID; i++ ) {
 		/* pmt_version は (N%32) の値を取るので、0 で初期化してはならない */
 		sp->program[i].pmt_version = -1;
+		/* cue は最大値で初期化(CUE <= STCとなると録画開始するため) */
+		sp->program[i].cue = INT64_MAX;
 	}
 	memset(sp->pid_sid_table, 0, sizeof(int)*MAX_PID);
-//	sp->filename = filename;
 	if ( filename != NULL ) {
 		sp->esout = 1;
 		sp->filename = filename;
 	}
+	if ( arg_cue != NULL ) {
+		sp->arg_cue = arg_cue;
+	} else {
+		sp->arg_cue = "00000000000000"; /* とりあえず最小値 */
+	}
 	return sp;
 }
 
@@ -270,6 +280,7 @@
  */
 void split_shutdown(splitter* sp)
 {
+	int i = 0;
 	if ( sp != NULL ) {
 		if ( sp->pat != NULL )
 		{
@@ -281,6 +292,20 @@
 			free(sp->sid_list);
 			sp->sid_list = NULL;
 		}
+		for(i=0; i < MAX_PID; i++) {
+			if ( sp->esbuf[i] != NULL ) {
+				if ( sp->esbuf[i]->fd != -1 ) {
+					close(sp->esbuf[i]->fd);
+					sp->esbuf[i]->fd = -1;
+				}
+				free(sp->esbuf[i]);
+				sp->esbuf[i] = NULL;
+			}
+			if ( sp->pesbuf[i] != NULL ) {
+				free(sp->pesbuf[i]);
+				sp->pesbuf[i] = NULL;
+			}
+		}
 		free(sp);
 		sp = NULL;
 	}
@@ -294,13 +319,8 @@
 static int ReadTs(splitter *sp, ARIB_STD_B25_BUFFER *sbuf)
 {
 #if 0
-	unsigned char **pat,				// [out]	PAT 情報(再構築後)
-	unsigned char* pids,				// [out]	出力対象 PID 情報
-	char** sid_list,					// [in]		出力対象サービス ID のリスト
-	unsigned char* pmt_pids,			// [in]		出力対象PIDのPMT PID
-	,			// [in]		pt1_drvの入力TS
-	int* pmt_retain,						// [in]		PMTの落とすべき数
-	int* pmt_counter					// [out]	PMTの落とした数
+	splitter *sp,						// [in/out]		splitter構造体
+	ARIB_STD_B25_BUFFER *sbuf,			// [in]		pt1_drvの入力TS
 #endif
 
 	int length = sbuf->size;
@@ -313,7 +333,6 @@
 		pid = GetPid(sbuf->data + index + 1);
 		// PAT
 		if(PAT == pid) {
-			dump_packet(sbuf->data + index);
 			result = AnalyzePat(sp, sbuf->data + index);
 			if(TSS_SUCCESS != result) {
 				/* 下位の関数内部でmalloc error発生 */
@@ -325,20 +344,12 @@
 		/* 残すpmt_pidである場合には、pmtに書かれている
 		 * 残すべきPCR/AUDIO/VIDEO PIDを取得する */
 		if(sp->pmt_pids[pid] == 1) {
-			/*
-			 * program(番組)とServiceID をベースに管理することにしているので、
-			 * pmt_pidsとかもう必要ないかも…
-			 */
 			/* この中にはPMT毎に一度しか入らないようにしておく */
-			int random_access;
-			//AnalyzePmt(sp, sbuf->data + index, pid);
-			//AnalyzePmt(sp, sbuf->data + index +4, pid, LENGTH_PACKET-4);
 			sp->pmt_pids[pid]++;
 			sp->pmt_counter += 1;
-			DemuxTs(sbuf->data +index, sp, pid, &random_access); /* AnalyzePmt より DemuxTs の方がアダプテーションフィールドの処理が良いので変更 */
+			DemuxTs(sbuf->data +index, sp, pid); /* AnalyzePmt より DemuxTs の方がアダプテーションフィールドの処理が良いので変更 */
 		}
-		/* 録画する全てのPMTについて、中にあるPCR/AUDIO/VIDEOのPIDを
-		 * 得る */
+		/* 録画する全てのPMTについて、中にあるPCR/AUDIO/VIDEOのPIDを得る */
 		/* pmt_counter と pmt_retain が一致する場合に条件は満たされる */
 		if(sp->pmt_counter == sp->pmt_retain) {
 			result = TSS_SUCCESS;
@@ -357,23 +368,22 @@
  * TS 分離処理
  */
 int split_ts(
-	splitter *splitter,					// [in]		splitterパラメータ
+	splitter *sp,						// [in]		splitterパラメータ
 	ARIB_STD_B25_BUFFER *sbuf,			// [in]		入力TS
-	splitbuf_t *dbuf							// [out]	出力TS
+	splitbuf_t *dbuf					// [out]	出力TS
 )
 {
 	int pid;
 	unsigned char *sptr, *dptr;
 	int s_offset = 0;
 	int d_offset = 0;
-	int64_t pcr;
-	int64_t pcr_h;
-	int pcr_l;
-	struct timespec tot_timespec;
-	struct timespec local_timespec;
-	int len_pes;
-	int random_access;
-	int sid;
+	int64_t pcr_h = 0;
+	int pcr_l = 0;
+	int ret = 0;
+	int sid = 0;
+	program_t *program;
+	static int packet_nb;		/* パケット受信数 */
+	int i = 0;
 
 	/* 初期化 */
 	dbuf->size = 0;
@@ -383,135 +393,162 @@
 
 	sptr = sbuf->data;
 	dptr = dbuf->buffer;
-#if 0
-	/* TOT受信済みであるなら、STC を成長させる */
-	if ( sp->tot_offset.tv_nsec != 0 && sp->tot_offset.tv_sec != 0) {
-		forward_stc(&(sp->STC_timespec), sp->tot_offset);
-	}
-#endif
 
 	while(sbuf->size > s_offset) {
 		pid = GetPid(sptr + s_offset + 1);
-		sid = splitter->pid_sid_table[pid];
+		sid = sp->pid_sid_table[pid]; /* PIDからSIDを取得 */
 		switch(pid) {
 
 		// PAT
 		case PAT:
 			// 巡回カウンタカウントアップ
-			if(0xFF == splitter->pat_count) {
-				splitter->pat_count = splitter->pat[3];
+			if(0xFF == sp->pat_count) {
+				sp->pat_count = sp->pat[3];
 			}
 			else {
-				splitter->pat_count = (splitter->pat_count + 1) % 16;
+				sp->pat_count += 1;
+				if(0 == sp->pat_count % 0x10) {
+					sp->pat_count -= 0x10;
+				}
 			}
-			splitter->pat[3] = splitter->pat_count;
+			sp->pat[3] = sp->pat_count;
 
-			memcpy(dptr + d_offset, splitter->pat, LENGTH_PACKET);
+			memcpy(dptr + d_offset, sp->pat, LENGTH_PACKET);
 			d_offset += LENGTH_PACKET;
 			dbuf->size += LENGTH_PACKET;
 			break;
-		case TOT: 
+		case TOT:
 			/* TOT に TDTの情報全てが含まれており、実放送では TOT しか送信されない */
 			/* TOT は 500msec の誤差が保証されている
 			 * 閏秒の場合は最大1.5秒の誤差となる
 			 */
-#if 0
-			if ( sp->tot_offset.tv_nsec != 0 && sp->tot_offset.tv_sec != 0 ) {
-				parse_tot(sptr + s_offset, &(tot_timespec.tv_sec));
-				clock_gettime(CLOCK_REALTIME, &local_timespec);
-
-				/* TOT をSystem Time Clock(STC)に入れる */
-				sp->STC_timespec.tv_sec = tot_timespec.tv_sec;
-				sp->STC_timespec.tv_nsec = tot_timespec.tv_nsec;
-
-				/* TOT と localtime の差分を sp->tot_offset に入れる */
-				sp->tot_offset.tv_sec = tot_timespec.tv_sec - local_timespec.tv_sec;
-				sp->tot_offset.tv_nsec = tot_timespec.tv_nsec - local_timespec.tv_nsec;
-			}
-#endif
-			/* STC が既にあるならTOT受信時に頭出し時刻を決定する */
-			/* 59秒9990 あたりを頭出し時刻に設定でよいかな */
-			if ( splitter->stc != 0 && splitter->cue_time == -1) {
-				/* TOT から cue_time を計算する */
-				/* えいや。で、59秒9990固定決め打ち */
-				parse_tot(sptr + s_offset, &(tot_timespec.tv_sec));
-				//cue_second = ((tot_timespec.tv_sec % 60) - 59);
-				splitter->cue_time = splitter->stc + (((59 - (tot_timespec.tv_sec % 60))*(27*1000*1000)) + floor((27*1000*1000)*0.999));
-				//printf("stc[%lld]. cue_time[%lld].\n", splitter->stc, splitter->cue_time);
-
-			} else {
-				/* TOT受診時にSTCが存在しないならTOTは捨てる */
+			if ( sp->time_tot == 0 ) {
+				/* splitter構造体の時刻関係(TOT/CUE)のパラメータ初期化 */
+				parse_tot(sptr + s_offset, &(sp->time_tot));
+				sp->time_cue = cue2time(sp->arg_cue);
+				sp->tot_packet_nb = packet_nb;
 			}
 			break;
 		default:
-			/* 時間管理に関しての実装方針 */
+			/* ■時間管理に関しての実装方針■ */
 			/*
-			 * 時間関係を扱っている変数のまとめ
-			 * PCR : 42Bit @27MHz(プログラム毎に独立)
-			 * PTS : 42Bit @90KHz(SYSTEM ID(ES)毎に独立)
-			 * DTS : 42Bit @90KHz(SYSTEM ID(ES)毎に独立)
-			 * TOT : MJD + 2進化10進数(ストリームに一つだけ)
-			 * STC : 64Bit @27MHz(システムローカル時刻(ソースはTOT))
+			 * ■時間関係を扱っている変数■
+			 * PCR : 42Bit @27MHz(ServiceID(ProgramID, sid)毎に独立)
+			 * PTS : 42Bit @90KHz(ES毎に独立)
+			 * DTS : 42Bit @90KHz(ES毎に独立)
+			 * TOT : MJD + 2進化10進数(TSに1つだけ)
+			 * STC : 64Bit @27MHz(ServiceID(ProgramID, sid)の現在時刻(ソースはPCR))
+			 * CUE : 録画開始時刻 YYYYMMDDHHMISS (引数指定)
+			 *
+			 * ■STCの管理方針■
+			 * PCR受信時にSTCに時間情報をコピーする
+			 * 1パケットを受信すると経過する時間を加算してSTCを管理する
+			 * (ffmpegのmpegts.cと同じ方針)
 			 *
-			 * STC と TOT の関連だけ計算出来るようにしておいて、
-			 * 出力するようにする/しないの判定は全体的に、
-			 * STCからTOTを使って出した時刻情報とする。かなぁ。
-			 * PCR/PTS/DTSはオーバーフローしたときには34Bit目が立っていると見なすこと
+			 * ■CUEとTOTとSTC■
+			 * TOTからSTCと比較するための情報を作成する。
+			 * ・TOTは time_t
+			 * ・CUEは time_t
+			 * ・STCは42Bitの27MHz周期の数値
+			 * TOT 受信時に各Program(ServiceID)のSTCを変換基準値とする
+			 * 録画開始時(27MHz)の値の計算式は、
+			 *   Program->CUE = STCの変換基準値 + 27e6*(ARG_CUE-TOT(秒))
+			 * 録画の開始確認として Program->CUE と PTS を比較すればよい
+			 *
+			 * ※PCR/PTS/DTSはオーバーフローしたときには34Bit目が立っていると見なすこと※
+			 * オーバーフロー時の処理は未実装
 			 */
-//			if ( 1 == splitter->pmt_pids[pid] ) {
-			if ( 2 == splitter->pmt_pids[pid] ) {
+			if ( 2 == sp->pmt_pids[pid] ) {
 				/* PMT の追跡 */
-				int random_access;
-				DemuxTs((sptr+s_offset), splitter, pid, &random_access);
+				DemuxTs((sptr+s_offset), sp, pid);
 			}
 			/* pids[pid] が 1 は残すパケットなので書き込む */
-			if ( 1 == splitter->pids[pid] ) {
-				len_pes = 0;
-				random_access = 0;
-				/* PCR 解析テスト */
-				if (parse_pcr(&pcr_h, &pcr_l, (sptr+s_offset)) == 0){
-					pcr = pcr_h * 300 + pcr_l;
-					/* PCR の種にするものは、Program の PCR として指定されたPacketIDのものとすること */
-					/* STC は PCR を種にする */
-					splitter->stc = pcr;
-//					printf("PID[%d] pcr_h=[%llx] pcr_l=[%d] PCR[%f]\n",pid, pcr_h, pcr_l, ((double)pcr/(90000*300)));
-				}
-				/* TS処理 */
-				if (DemuxTs((sptr+s_offset), splitter, pid, &random_access) == 0 ) {
-#if 0
-					/* とりあえずやっつけ */
-					/* パケットの画面表示時刻(pts) >= 録画開始時刻(cue_time) となった場合に録画開始 */
-//					if ( ((pts*300) >= splitter->cue_time)  && (splitter->cue_time != -1)) {
-					if ( ((splitter->esbuf[pid].pts) >= splitter->program[sid].cue_time)  && (splitter->program[sid].cue_time != -1)) {
-						splitter->cue_time = 0;
-						splitter->status = 0;
-						clock_gettime(CLOCK_REALTIME, &local_timespec);
-						printf("start recording. time_sec[%d] nsec[%d].\n", local_timespec.tv_sec%60, local_timespec.tv_nsec);
-					}
-#endif
-				}
-				//search_mpeg_system_header(sptr+s_offset);
-				/*
-				 * STCが cue_time を経過したら録画開始
-				 */
-				if ( splitter->cue_time != -1 && splitter->cue_time <= splitter->stc ) {
-					memcpy(dptr + d_offset, sptr + s_offset, LENGTH_PACKET);
-					d_offset += LENGTH_PACKET;
-					dbuf->size += LENGTH_PACKET;
-					if ( splitter->status ) {
-						struct timespec local_timespec;
-						clock_gettime(CLOCK_REALTIME, &local_timespec);
-						printf("start recording. time_sec[%d] nsec[%d].\n", local_timespec.tv_sec%60, local_timespec.tv_nsec);
-						splitter->status = 0;
+			if ( (1 == sp->pids[pid]) ) {
+				/* PCRとSTCの処理 */
+				int pcr_index;
+				pcr_index = search_pcr_pid(sp, pid);
+				if ( sp->pcr_pids[pid] == 1 && pcr_index != -1) { /* PCRか否か */
+					ret = parse_pcr(&pcr_h, &pcr_l, (sptr+s_offset));
+					/*
+					 * PCR は複数 ServiceID(ProgramID)で重複利用される場合がある
+					 * PCR を参照する複数の ServiceID(ProgramID)分ループ
+					 */
+					for (i=0; i < sp->pcr[pcr_index].sid_nb; i++) {
+						sid = sp->pcr[pcr_index].sid[i];
+						program = &(sp->program[sid]);
+						/* こっから */
+						if ( ret == 0 ) { /* PCR の解析に成功 */
+							program->stc = pcr_h * 300 + pcr_l; /* PCR受信時にSTCを補正*/
+							if ( program->pcr1 == 0 ) {
+								program->pcr1 = program->stc;
+								printf("pcr1 pid[%d] sid[%d] packet_nb[%d] sid_nb[%d] i[%d]\n",
+										pid, sid, packet_nb, sp->pcr[pcr_index].sid_nb, i);
+							} else if ( program->pcr2 == 0 ) {
+//								printf("pcr2 pid[%d] sid[%d] packet_nb[%d], p_packet_nb[%d] sid_nb[%d] i[%d]\n",
+//										pid, sid, packet_nb, program->pcr_packet_nb, sp->pcr[pcr_index].sid_nb, i);
+								program->pcr2 = program->stc;
+								program->pcr_incr = (program->pcr2 -program->pcr1)
+									/(packet_nb -program->pcr_packet_nb);
+								printf("pcr2 pid[%d] sid[%d] pcr_incr[%llu]\n",
+										pid, sid, program->pcr_incr);
+							} else {
+								/* PCR処理済み */
+								; /* 得に処理無し */
+							}
+							if ( (program->cue == INT64_MAX ) &&
+									(sp->arg_cue != NULL) &&
+									(sp->time_tot != 0) ) { /* 録画開始時刻指定時 */
+								/*
+								 * 録画開始時刻 = STC +(CUE -TOT)*27MHz
+								 * +(TOT取得時から現在までのパケット数の増分)*パケットあたりの進む時間
+								 * -0.49秒(この数字は適当)
+								 * TOT/STCで時間調整して、GOP先頭から出すので攻めてしまっていい気がする
+								 */
+								program->cue = program->stc
+									+(sp->time_cue -sp->time_tot)*27e6
+									+(packet_nb -sp->tot_packet_nb)*program->pcr_incr
+									-(27e6*49/100);
+								printf("STC[%llu] CUE[%llu] SID[%d]\n",
+										program->stc, program->cue, sid);
+							}
+							program->pcr_packet_nb = packet_nb;
+							program->packet_nb = packet_nb;
+						} else if ( program->pcr_incr ) { /* PCRの解析に失敗且つpcr_incr変数の計算済み*/
+							/* STCを成長させる */
+							program->stc += (packet_nb -program->packet_nb)*program->pcr_incr;
+							program->packet_nb = packet_nb;
+						} else {
+							; /* STCを進める要素が揃ってません */
+						}
+					} /* for */
+				} else { /* 処理対象パケットはPCRではない */
+					program = &(sp->program[sid]);
+					if ( program->pcr_incr ) { /* PCRを受信しない且つpcr_incr変数の計算済み */
+						/* STCを成長させる */
+						program->stc += (packet_nb -program->packet_nb)*program->pcr_incr;
+						program->packet_nb = packet_nb;
+					} else { /* それ以外 */
+						; /* STCを進める要素が揃ってません */
 					}
 				}
+#if 0
+// NHK Gを ALL とすると SID 1024 しか出ない...orz..
+				if ( !(packet_nb % 1000) ) {
+					program = &(sp->program[sid]);
+					printf("STC[%llu] SID[%d]\n", program->stc, sid);
+				}
+#endif
+				/* TS処理 */
+				DemuxTs((sptr+s_offset), sp, pid);
+				memcpy(dptr + d_offset, sptr + s_offset, LENGTH_PACKET);
+				d_offset += LENGTH_PACKET;
+				dbuf->size += LENGTH_PACKET;
 			}
 			break;
 		} /* switch */
-
 		s_offset += LENGTH_PACKET;
+		packet_nb += 1; /* パケット受信数加算 */
 	}
-
 	return(TSS_SUCCESS);
 }
 
@@ -574,6 +611,7 @@
 				if(service_id == atoi(*p)) {
 					/* 録画対象の pmt_pids は 1 とする */
 					/* 録画対象の pmt の pids は 1 とする */
+					/* 対応する pid_sid_table に サービスID(ProgramID) を入れる */
 					pid = GetPid(&buf[i + 2]);
 					*(pmt_pids+pid) = 1;
 					*(pids+pid) = 1;
@@ -782,6 +820,7 @@
 	return(TSS_SUCCESS);
 }
 
+
 /**
  * PMT 解析処理
  *
@@ -800,22 +839,113 @@
 	int pcr;
 	int epid;
 	int av_flag = 0;
+	int i = 0;
+	int j = 0;
+	int pcr_found = 0;
+/* デバッグ用 PMT情報表示 */
+#define PmtDebug (1)
+
+#ifdef PmtDebug
+	printf("AnalyzePmt start. Tree List enable.\n");
+	printf("SID[%d][0x%04x]\n", sid, sid);
+#endif
 
 //	Nall = ((buf[2] & 0x0F) << 4) + buf[3];
 	Nall = ((buf[2] & 0x0F) << 8) + buf[3];
+// ここで受け取るのはTSパケットではなく、セクションの先頭ポインタであるのでsizeで見る
+//	if(Nall > LENGTH_PACKET)
+//		Nall = LENGTH_PACKET - 8; /* xxx workaround --yaz */
+	if(Nall > size)
+		Nall = size -8;
 
 	/* get version */
 	sp->program[sid].pmt_version = get_pmt_version(buf);
+#ifdef PmtDebug
+	printf("	pmt_version[%02x]\n", sp->program[sid].pmt_version);
+#endif
 
 	// PCR
 	pcr = GetPid(&buf[9]);
 	sp->pids[pcr] = 1;
 	sp->program[sid].pcr_packet_id = pcr;
+	sp->pid_sid_table[pcr] = sid; /* PCRは重複する可能性があるので方式がよろしくない */
+	sp->pcr_pids[pcr] = 1;
+
+	/* PCRの重複チェック(複数ServiceID(ProgramID)) */
+	for( i=0; i < sp->pcr_nb; i++ ) {
+		if ( sp->pcr[i].pid == pcr ) {
+			/* 発見 */
+			for ( j=0; j < sp->pcr[i].sid_nb; j++ ) {
+				/* 同一SIDが既に登録されているか確認 */
+				if ( sp->pcr[i].sid[j] == sid ) {
+					pcr_found = 1;
+					break;
+				}
+			}
+			if ( pcr_found ) {
+				/* 同一SIDが既に登録されている */
+#ifdef PmtDebug
+				printf("	same sid found pcr[%d] sid[%d]\n", pcr, sid);
+#endif
+				break;
+			}
+			/* 重複PCR発見 */
+#ifdef PmtDebug
+			printf("	same pcr found pcr[%d] sid[%d] sid_nb[%d], i[%d]\n", pcr, sid, sp->pcr[i].sid_nb, i);
+#endif
+			sp->pcr[i].sid[sp->pcr[i].sid_nb] = sid;
+			sp->pcr[i].sid_nb += 1;
+			pcr_found = 1;
+			break;
+		}
+	}
+
+	if ( ! pcr_found ) {
+		/* PCR管理領域更新 */
+#ifdef PmtDebug
+		printf("	new pcr found pcr[%d] sid[%d], pcr_nb[%d]\n", pcr, sid, sp->pcr_nb);
+#endif
+		sp->pcr[sp->pcr_nb].pid = pcr;
+		sp->pcr[sp->pcr_nb].sid[0] = sid;
+		sp->pcr[sp->pcr_nb].sid_nb = 1;
+		sp->pcr_nb += 1;
+	}
+#ifdef PmtDebug
+	printf("	PCR PacketID[%d][0x%04x]\n", pcr, pcr);
+#endif
 
 //	N = ((buf[11] & 0x0F) << 4) + buf[12] + 16 + 1;
 	N = ((buf[11] & 0x0F) << 8) + buf[12] + 12 + 1;
 //	printf("NAll[%d] N[%d]\n", Nall, N);
 
+	// ECM
+	//int p = 17;
+	int p = 13;
+	while(p < N) {
+		if ( p > size -4) {
+			break;
+		}
+		uint32_t cat_pid;
+		uint32_t tag;
+		uint32_t len;
+
+		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;
+			cat_pid = (AV_RB16(buf+p+2)) & 0x1fff;
+			sp->pids[cat_pid] = 1;
+			sp->cat_pids[cat_pid] = 1;
+			sp->pid_sid_table[cat_pid] = sid; /* CATも複数ServiceIDで重複がある */
+#ifdef PmtDebug
+			printf("	CAT PacketID[%d][0x%04x]\n", cat_pid, cat_pid);
+#endif
+		}
+		p += len;
+	}
+
 	/*
 	 * ISO/IEC 13818-1:2000(E) Table 2-29 - Stream type assignments
 	 * Value Desctiption
@@ -846,30 +976,35 @@
 	 */
 
 	// ES PID
-	while (N < Nall + 8 - 4)
-	{
+	while (N < Nall + 8 - 4) {
 		av_flag = 0;
-		if ( N > size ) {
-			break;
-		}
 		// ストリーム種別が 0x0D(type D)は出力対象外
-		if (0x0D != buf[N])
-		{
+		if (0x0D != buf[N]) {
 			epid = GetPid(&buf[N + 1]);
 			sp->pids[epid] = 1;
+			sp->pid_sid_table[epid] = sid;
 			if ( buf[N] == 0x02 ) { /* 13818-2 Video */
 				sp->program[sid].video[sp->program[sid].video_nb] = epid;
 				sp->program[sid].video_nb += 1;
-				av_flag = 1;
+				av_flag = TSS_STREAM_TYPE_VIDEO;
+#ifdef PmtDebug
+				printf("	VIDEO PacketID[%d][0x%04x] StreamType[0x%02x]\n", epid, epid, buf[N]);
+#endif
 			} else if ( (buf[N] == 0x04) || (buf[N] == 0x0f) ) {
 				/* 13818-3 Audio or 13818-7 Audio with ADTS transport syntax */
 				sp->program[sid].audio[sp->program[sid].audio_nb] = epid;
 				sp->program[sid].audio_nb += 1;
-				av_flag = 2;
+				av_flag = TSS_STREAM_TYPE_AUDIO;
+#ifdef PmtDebug
+				printf("	AUDIO PacketID[%d][0x%04x] StreamType[0x%02x]\n", epid, epid, buf[N]);
+#endif
 			} else {
+#ifdef PmtDebug
+				printf("	OTHER PacketID[%d][0x%04x] StreamType[0x%02x]\n", epid, epid, buf[N]);
+#endif
 				; /* A/V どちらでもないものはとりあえずスルー */
 			}
-			if ( av_flag ) {
+			if ( av_flag && sp->esout ) {
 				/* ESバッファはNULLか? */
 				if ( sp->esbuf[epid] == NULL ) {
 					sp->esbuf[epid] = malloc(sizeof(splitesbuf_t));
@@ -879,8 +1014,10 @@
 					}
 					sp->esbuf[epid]->size = 0;
 					sp->esbuf[epid]->Program = &(sp->program[sid]);
-//					creat_filename(sp->filename, sp->esbuf[epid]->filename, sid, epid, av_flag, &(sp->esbuf[epid]));
-					creat_filename(sp, sid, epid, av_flag);
+					sp->esbuf[epid]->fd = -1;
+					if ( creat_es_file(sp, sid, epid, av_flag) ) {
+						return TSS_ERROR;
+					}
 				}
 				/* PESバッファはNULLか? */
 				if ( sp->pesbuf[epid] == NULL ) {
@@ -897,6 +1034,9 @@
 //		N += 4 + (((buf[N + 3]) & 0x0F) << 4) + buf[N + 4] + 1;
 		N += 4 + (((buf[N + 3]) & 0x0F) << 8) + buf[N + 4] + 1;
 	}
+#ifdef PmtDebug
+	printf("AnalyzePmt finish.\n");
+#endif
 	return TSS_SUCCESS;
 }
 
@@ -994,7 +1134,6 @@
 /* pesbufにデータを追加 (ret. 0:success / -1:error) */
 static int pesbuf_add(splitpesbuf_t *pesbuf, const uint8_t *data, int len){
 	if(pesbuf->size + len > sizeof pesbuf->buffer){
-		//assert(0);
 		return -1;
 	}
 	memcpy(pesbuf->buffer +pesbuf->size, data, len);
@@ -1033,7 +1172,7 @@
 /**
  * TSの解析とDemuxを行う
  */
-static int DemuxTs(const uint8_t *packet, splitter *sp, const int pid, int *random_access)
+static int DemuxTs(const uint8_t *packet, splitter *sp, const int pid)
 {
 	/*
 	 * PES先頭までの長さは
@@ -1049,8 +1188,8 @@
 	int pes_started;
 	int adaptation_field_control;
 	int payload_unit_start_indicator;
-	int random_access_indicator = 0;
-	int sid = sp->pid_sid_table[pid];
+//	int random_access_indicator = 0;
+	int sid = sp->pid_sid_table[pid]; /* SIDをPIDから引いているが、PCRとCATは重複しているので注意*/
 
 	payload_offset = LENGTH_TS_HEADER;
 
@@ -1068,7 +1207,7 @@
 	} else if ( adaptation_field_control == 0x03 ) {
 		/* アダプテーションフィールド+ペイロードの場合 */
 		if ( packet[LENGTH_TS_HEADER] != 0 ) {
-			random_access_indicator = (packet[5] & 0x40) >> 6;
+//			random_access_indicator = (packet[5] & 0x40) >> 6;
 		}
 		/* ペイロード開始位置 = TSヘッダ長 + アダプテーションフィールド長 + 1 */
 		payload_offset += packet[LENGTH_TS_HEADER] + 1;
@@ -1100,6 +1239,17 @@
 		}
 		return 0; /* PMT の場合は処理終わり */
 	}
+	if ( !sp->esout ) {
+		/* ES出力しない場合はPES蓄積不要 */
+		return 0;
+	}
+	if ( sp->cat_pids[pid] == 1 ) {
+		return 0; /* CATは蓄積しない */
+	}
+	if ( sp->pesbuf[pid] == NULL ) {
+		/* PES蓄積不要である場合も蓄積しない */
+		return 0;
+	}
 
 	/* payload_unit_start_indicatorを処理(2) */
 	/* 必要に応じ、蓄積済みPESの処理と、PES蓄積開始を行う */
@@ -1107,7 +1257,8 @@
 		/* PES開始 */
 		if ( pes_started ) {
 			/* バッファにデータがあればPES終端なので処理してクリア */
-			pes2es(sp->pesbuf[pid], sp->esbuf[pid], pid, random_access_indicator);
+//			pes2es(sp->pesbuf[pid], sp->esbuf[pid], pid, random_access_indicator);
+			pes2es(sp->pesbuf[pid], sp->esbuf[pid], pid);
 			pesbuf_clear(sp->pesbuf[pid]);
 		}
 		else {
@@ -1124,6 +1275,8 @@
 	return 0;
 }
 
+#if 0
+未使用なため削除
 /* PMT_PID から Program(Service ID)を確定させる */
 static int search_pmt_program(splitter *sp, int pid)
 {
@@ -1136,6 +1289,7 @@
 	}
 	return -1;
 }
+#endif
 
 /* esbufが空か判定 (ret. 0:not empty / 1: empty) */
 static int esbuf_empty(splitesbuf_t *esbuf){
@@ -1143,9 +1297,10 @@
 }
 
 /* esbufをクリア */
-void esbuf_clear(splitesbuf_t *esbuf){
-	esbuf->random_access_indicator = 0;
+void esbuf_clear(splitesbuf_t *esbuf, uint64_t pts, uint64_t dts){
 	esbuf->size = 0;
+	esbuf->pts = pts;
+	esbuf->dts = dts;
 }
 
 /* esbufにデータを追加 (ret. 0:success / -1:error) */
@@ -1161,7 +1316,8 @@
 /*
  * PESを解析してESを出力する
  */
-static int pes2es(splitpesbuf_t *pesbuf, splitesbuf_t *esbuf, const int pid, int random_access_indicator)
+//static int pes2es(splitpesbuf_t *pesbuf, splitesbuf_t *esbuf, const int pid, int random_access_indicator)
+static int pes2es(splitpesbuf_t *pesbuf, splitesbuf_t *esbuf, const int pid)
 {
 	int len_pesh = 0;
 	int code = 0;
@@ -1184,7 +1340,8 @@
 	int64_t audio_pts = 0;
 	int adts_freq = 0;
 	int64_t adts_frame_time = 0;
-	int audio_accumulation = 0;
+	int gop_start = -1;
+
 	/* ありがとう */
 	/* ありがとうとコメントを書くと、
 	 * 動作がよくなる
@@ -1397,61 +1554,83 @@
 			len_pesh_supposed += pes_extension_flags2;
 		}
 	}
+	if ( pid != 6417 && pid != 6418 ) {
+//		printf("es start? pid[%d]\n", pid);
+	}
+	/* ES蓄積管理処理 */
 	payload_length = pesbuf->size -payload_offset;
-	if ( data_alignment_indicator ) {
+//	if ( data_alignment_indicator ) { /* data_alignment_indicator 区切りでESを出力する */
 		if ( es_started ) { /* ES にデータが蓄積されている */
-			if ( is_video_stream(pid, esbuf) && !(esbuf->started) ) { /* VIDEO である場合 */
-				/* random_access ビットが立っている場合は、GOP先頭である */
-				if ( random_access_indicator ) { /* TS の random_access ビットが立ったものがきているか? */
-					/* 該当ストリームを蓄積開始する */
+			/*
+			 * ビデオをファイル出力し始める条件(1. 2. を満たすこと)
+			 * 1. ESにGOP先頭を含む
+			 * 2. PTSがCUEの時刻を過ぎていること( CUE <= PTS )
+			 */
+			if ( (is_video_stream(pid, esbuf) == 0) && !(esbuf->started) ) {
+				/* VIDEO0 を同期の基準とする */
+				gop_start = search_gop_start_code(esbuf);
+				if ( (gop_start != -1) && /* ESバッファにGOP_START_CODEが存在するか? */
+						(esbuf->Program->cue <= esbuf->pts*300) ) { /* CUEを過ぎている? */
+					/* 該当ストリームをファイル出力開始する */
 					esbuf->started = 1;
 					esbuf->Program->video_start = 1;
 					esbuf->Program->video_pts = esbuf->pts;
 					printf("video stream. pid[%d] v_pts[%llu].\n", pid, esbuf->pts);
 				} else {
-					/* TS の random_access ビットが立ったものがきていない */
-					/* 蓄積開始しない */
-					esbuf_clear(esbuf);
-					esbuf->pts = pesbuf->pts;
-					esbuf->dts = pesbuf->dts;
+					/* GOP先頭を含まないものはクリア */
+					esbuf_clear(esbuf, pesbuf->pts, pesbuf->dts);
+				}
+			} else if ( (is_video_stream(pid, esbuf) != -1) && !(esbuf->started) ) {
+				/* VIDEO0 以外のものはVIDEO0 が開始するまでクリア */
+				if ( !(esbuf->Program->video_start) ) {
+					/*
+					 * VIDEO0 が始まってない場合、
+					 * VIDEON は常にクリア
+					 */
+					esbuf_clear(esbuf, pesbuf->pts, pesbuf->dts);
+				} else {
+					/*
+					 * VIDEO0 が始まっている場合、
+					 * VIDEON の録画を開始
+					 */
+					esbuf->started = 1;
 				}
 			}
-			/* AAC の実験コードここから */
 			/*
-			 * オーディオを出力し始める条件(1. 2. を満たすこと)
+			 * オーディオをファイル出力し始める条件(1. 2. を満たすこと)
 			 * 1. 動画の蓄積は開始されている
 			 * 2. 動画のGOPの1番目のIピクチャのPTSとオーディオのPTSを比較して以下のどちらかを満たすこと
-			 *    2.1. 差分が11msec以内
+			 *    2.1. 差分が11msec以内(1000*90k/AACのサンプリング周波数)
+			 *         1000 : ADTSデータの1フレームのサンプル数
+			 *         90k  : PTSの周波数
 			 *    2.2. 過ぎている(過ぎている場合はオーディオESの蓄積の継続と次のGOP狙いにする?)
-			 *    #GOP先頭にこだわり過ぎると録画を逃すという線もあるので、適当に手を打つのも手
+			 *    #動画よりオーディオ側の方が先にESバッファの蓄積を始めるハズなので気にすること無いかなぁ…
 			 */
-			else if ( (is_audio_stream(pid, esbuf) != -1 ) && !(esbuf->started) ) {
+			else if ( (is_audio_stream(pid, esbuf) != -1) && !(esbuf->started) ) {
 				if ( !(esbuf->Program->video_start) ) {
 					/*
 					 * VIDEO が始まってない場合、
-					 * ESバッファの余裕がある限り蓄積続けちゃえばいいんでない?
+					 * ESバッファの余裕がある限り、オーディオをESバッファに蓄積し続ける
 					 */
-					audio_accumulation = 1; /* ESバッファにオーディオを追記する */
-					if ( esbuf->size > sizeof esbuf->buffer -payload_length ){
+					if ( esbuf->size + payload_length > sizeof esbuf->buffer ){
 						/* 溢れそうになったらクリア */
-						esbuf_clear(esbuf);
-						esbuf->pts = pesbuf->pts;
-						esbuf->dts = pesbuf->dts;
-						audio_accumulation = 0;
+						esbuf_clear(esbuf, pesbuf->pts, pesbuf->dts);
 					}
-				}
-				else if ( esbuf->Program->video_start ) { /* video 蓄積が開始されているので音声側の頭を揃える */
-					printf("audio stream. pid[%d] a_pts[%llu] v_pts[%llu].\n", pid, esbuf->pts, esbuf->Program->video_pts);
+				} else if ( esbuf->Program->video_start ) { /* video 蓄積が開始されている?*/
+					printf("audio stream. pid[%d] a_pts[%llu] v_pts[%llu] size[%d].\n", pid, esbuf->pts, esbuf->Program->video_pts, esbuf->size);
 					audio_lipsync_offset = 0;
 					audio_pts = esbuf->pts;
 					adts_freq = AnalyzeAdifHeader(esbuf);
 					adts_frame_time = (int64_t)((float)1000*90000/adts_freq); /* PTSは90KHz */
+					/* オーディオをフレーム単位で捨ててPTSを進める */
 					while ( (esbuf->Program->video_pts > audio_pts +adts_frame_time/2) ) {
 						/* オーディオデータを捨てると audio_pts は1フレーム分大きくなる */
-						i = esbuf_adts_start_code_prefix(esbuf, audio_lipsync_offset); /* 次のAACのデータを取得 */
+						i = next_adts_start_code(esbuf, audio_lipsync_offset); /* 次のAACのデータを取得 */
 						if ( i != -1 ) { /* AACデータの終端か? */
 							audio_lipsync_offset += i;
 						} else {
+							/* バッファ終端まで進めたが、オーディオPTSの方が古い場合ESバッファはクリアする */
+							esbuf_clear(esbuf, pesbuf->pts, pesbuf->dts);
 							break;
 						}
 						printf("audio stream drop. pid[%d] pts[%llu].\n", pid, audio_pts);
@@ -1463,33 +1642,30 @@
 								esbuf->buffer,
 								esbuf->size -audio_lipsync_offset);
 						esbuf->size -= audio_lipsync_offset;
-						esbuf->started = 1;
+						esbuf->started = 1; /* オーディオのファイル出力を有効化 */
 					}
-				}
-				else {
+				} else {
 					; /* 該当するものは無いはず */
 				}
+			} else {
+				/* 得に処理なし */
+				;
 			}
-			/* AAC の実験コードここまで */
 			/* バッファをファイルに出力してクリア */
-			if ( esbuf->started ) {
+			if ( esbuf->started ) { /* 該当ストリームはファイル出力の有効化をされている? */
 				esbuf_write(esbuf);
-				esbuf_clear(esbuf);
-				esbuf->pts = pesbuf->pts;
-				esbuf->dts = pesbuf->dts;
+				esbuf_clear(esbuf, pesbuf->pts, pesbuf->dts);
 			}
 		} else {
 			/* ES蓄積を新たに開始 */
 			es_started = 1;
+			esbuf->pts = pesbuf->pts;
+			esbuf->dts = pesbuf->dts;
 		}
-	}
+	//}
 
 	/* ES蓄積処理 */
 	if ( es_started ) {
-		if ( ! audio_accumulation ) { /* オーディオのESバッファへの蓄積をしていない */
-			esbuf->pts = pesbuf->pts;
-			esbuf->dts = pesbuf->dts;
-		}
 		/* ES蓄積開始済み(これからES蓄積開始を含む)なら、payloadをESとして追加 */
 		esbuf_add(esbuf, pesbuf->buffer +payload_offset, payload_length);
 	}
@@ -1497,61 +1673,52 @@
 	return 0;
 }
 
-/* PIDはesbufのAUDIO STREAMの一つであるか? */
+/* Program の N 番目の AUDIO STREAM であるかを返却する */
 static int is_audio_stream(const int pid, splitesbuf_t *esbuf)
 {
 	int i = 0;
-	int found = 0;
 	program_t* program = esbuf->Program;
 	while (i < program->audio_nb)
 	{
 		if (program->audio[i] == pid) {
-			found = 1;
-			break;
+			return i;
 		}
 		i++;
 	}
-	return found;
+	return -1;
 }
 
-/* PIDはesbufのVIDEO STREAMの一つであるか? */
+/* Program の N 番目の VIDEO STREAM であるかを返却する */
 static int is_video_stream(const int pid, splitesbuf_t *esbuf)
 {
 	int i = 0;
-	int found = 0;
 	program_t* program = esbuf->Program;
 	while (i < program->video_nb)
 	{
 		if (program->video[i] == pid) {
-			found = 1;
-			break;
+			return i;
 		}
 		i++;
 	}
-	return found;
+	return -1;
 }
 
 /*
  * ESをファイル出力する
+ * エラーハンドリングしてないね…
  */
-//int esbuf_write(splitesbuf_t *esbuf, int pid)
-int esbuf_write(splitesbuf_t *esbuf)
+static int esbuf_write(splitesbuf_t *esbuf)
 {
 	int remain = esbuf->size;
-//#define ES_FILE "/tmp/es.%d"
-//	char filename[1024];
-//	filename[0] = '\0';
-//	umask(0133);
-//	snprintf(filename, sizeof(filename), ES_FILE, pid);
-//	fd = open(filename, O_CREAT|O_APPEND|O_RDWR, 00644);
 	while(remain > 0)
 	{
 		remain -= write(esbuf->fd, esbuf->buffer+(esbuf->size-remain), remain);
 	}
-//	close(fd);
 	return 0;
 }
 
+#if 0
+未使用なため駆除
 /*
  * packet dump
  */
@@ -1581,6 +1748,7 @@
 	}
 	putchar('\n');
 }
+#endif
 
 /*
  * TOT の JST_time を解析する
@@ -1646,25 +1814,8 @@
 	return ((p[6] >> 1) & 0x1f);
 }
 
-
 #if 0
-void forward_stc(timespec *stc, timespec offset)
-{
-	struct timespec local_timespec;
-
-	clock_gettime(CLOCK_REALTIME, &local_timespec);
-
-	stc->tv_sec = local_timespec.tv_sec + offset.tv_sec;
-	stc->tv_nsec = local_timespec.tv_nsec + offset.tv_nsec;
-	if ( stc->tv_nsec >= 1 * 1000 * 1000 * 1000 ) {
-		stc->tv_nsec -= 1 * 1000 * 1000 * 1000;
-		stc->tv_sec += 1;
-	} else if ( stc->tv_nsec < 0 ) {
-		stc->tv_nsec = 1 * 1000 * 1000 * 1000 + stc->tv_nsec;
-		stc->tv_sec -= 1;
-	}
-}
-#endif
+未使用なため駆除
 void search_mpeg_system_header(const uint8_t *packet)
 {
 	int i;
@@ -1676,28 +1827,30 @@
 		}
 	}
 }
+#endif
 
 /*
  * この関数では、現在の仕様では、先頭位置の「次の」ADTS start codeまでの長さを返却する
- * ret == 0  : 仕様上あり得ない
+ * ret == 0  : 仕様上あり得ない(esbuf先頭はヘッダ先頭であるため)
  * ret >  0  : 見つかった場合
  * ret == -1 : 見つからなかった場合
  */
-static int esbuf_adts_start_code_prefix(splitesbuf_t *esbuf, int offset)
+static int next_adts_start_code(splitesbuf_t *esbuf, int offset)
 {
 	/*
-	 * start code prefix のうち、先頭12bit は 1 固定であるが、13bit 目は id に該当
-	 * MPEG4なオーディオが来た場合に対応出来ないので、13bit 目は見ないように改造するべき
+	 * start code prefix のうち、先頭12bit は 1 固定
 	 */
-	uint8_t adts_start_code_prefix[2] = {0xFF, 0xF8}; /* とりあえず決め打ち */
+	uint16_t adts_start_code = 0xfff0;
 	int i = offset +1;
+	uint16_t startcode = 0;
 
 	/* 小さすぎる */
-	if(esbuf->size -offset < sizeof adts_start_code_prefix){
+	if(esbuf->size -offset < sizeof(adts_start_code)){
 		return -1;
 	}
-	for(; i < esbuf->size - sizeof adts_start_code_prefix; i++) {
-		if(!memcmp(esbuf->buffer + i ,adts_start_code_prefix, sizeof adts_start_code_prefix)){
+	for(; i < esbuf->size - sizeof(adts_start_code); i++) {
+		startcode = AV_RB16(esbuf->buffer+i);
+		if( startcode == adts_start_code ) { /* 該当位置から12bit連続1が立っているか? */
 #if 0
 			printf("adts start code found.i[%d]. 0[%02x] 1[%02x] 2[%02x] 3[%02x] 4[%02x] 5[%02x] 6[%02x]\n",
 					i, *(esbuf->buffer+i+0), *(esbuf->buffer+i+1), *(esbuf->buffer+i+2), *(esbuf->buffer+i+3), *(esbuf->buffer+i+4), *(esbuf->buffer+i+5), *(esbuf->buffer+i+6) );
@@ -1711,22 +1864,22 @@
 /* ADIF HEADER解析 */
 static int AnalyzeAdifHeader(splitesbuf_t *esbuf)
 {
-	int id = 0; /* 0:MPEG-4 1:MPEG-2 */
-	int layer = 0; /* 常に 0x00 */
-	int protection_absent = 0; /*保護属性 0:保護なし 1:保護あり */
-	int profile = 0; /* 00:MAIN 01:LC 10:SSR 11:(reserved) */
-	int sampling_frequency_index = 0;	/* サンプリング周波数テーブル値 */
-	int private_bit = 0;	/* private bit */
-	int channel_configuration = 0; /* チャンネル数 */
+	int id = 0;									/* 0:MPEG-4 1:MPEG-2 */
+	int layer = 0;								/* 常に 0x00 */
+	int protection_absent = 0;					/* 保護属性 0:保護なし 1:保護あり */
+	int profile = 0;							/* 00:MAIN 01:LC 10:SSR 11:(reserved) */
+	int sampling_frequency_index = 0;			/* サンプリング周波数テーブル値 */
+	int private_bit = 0;						/* private bit */
+	int channel_configuration = 0;				/* チャンネル数 */
 	int original_copy = 0;
-	int home = 0; /* homeってなに? */
-	int copyright_identification_bit = 0; /* 著作権証明ビット */
-	int copyright_identification_start = 0; /* 著作権証明開始ビット */
-	int aac_frame_length = 0; /* AACフレーム長 */
-	int adts_buffer_fullness = 0; /* ADTSバッファ残量 */
-	int no_raw_data_blocks_in_frame = 0; /* データブロックまでの残量 */
+	int home = 0;								/* homeってなに? */
+	int copyright_identification_bit = 0;		/* 著作権証明ビット */
+	int copyright_identification_start = 0;		/* 著作権証明開始ビット */
+	int aac_frame_length = 0;					/* AACフレーム長 */
+	int adts_buffer_fullness = 0;				/* ADTSバッファ残量 */
+	int no_raw_data_blocks_in_frame = 0;		/* データブロックまでの残量 */
 	/*
-	 * サンプリング周波数テーブル(ヘッダのINDEXが添字)
+	 * サンプリング周波数テーブル(ヘッダのsampling_frequency_indexが添字)
 	 * 単位:Hz
 	 */
 	int sampling_frequency_table[16] =
@@ -1847,10 +2000,11 @@
 	return (*p & 0x03);
 }
 
+#define GOP_START_CODE (0x000001b8)
 /* GOP START CODE を検索する */
 static int search_gop_start_code(splitesbuf_t *esbuf)
 {
-	uint8_t gop_start_code[4] = {0x00, 0x00, 0x01, 0xb8};
+	uint32_t gop_start_code = GOP_START_CODE;
 	int i;
 
 	/* 小さすぎる */
@@ -1858,25 +2012,26 @@
 		return -1;
 	}
 	for(i = 0; i < esbuf->size - sizeof gop_start_code; i++) {
-		if(!memcmp(esbuf->buffer +i ,gop_start_code, sizeof gop_start_code)){
+		if ( (AV_RB32(esbuf->buffer +i)) == gop_start_code ) {
 			return i;
 		}
 	}
 	return -1;
 }
 
-/* ES 出力するファイル名を決定する */
-//static int creat_filename(char *base, char *filename, int sid, int pid, int av_flag ,splitesbuf_t *esbuf)
-static int creat_filename(splitter *sp, int sid, int pid, int av_flag)
+/* ES 出力するファイルを作成する */
+static int creat_es_file(splitter *sp, int sid, int pid, int av_flag)
 {
 	/*
 	 * 出力ESファイルの命名規則は以下とする
 	 *
-	 * ファイル名のベースは出力TSファイル名
-	 * 出力先パスも出力TSファイル名から取得
-	 * ファイル名のうち、「.ts」を削除して、sidとepidをつけて、「.es」とする
-	 * .m2v とか .m2a とかそういう名前って好きではないのだけど...ISOに既定ないし
-	 * オーディオなのか、ビデオなのかって情報はあるけど
+	 * ファイル名のベースは --es オプションの引数
+	 * 以下の形式で命名して、ファイルオープンまで実施する。
+	 * ファイル名prefix_SID_AVのプログラム内番号.m2v
+	 * ファイル名prefix_SID_AVのプログラム内番号.aac
+	 *
+	 * !!注意!!
+	 * MPEG-2/MPEG-4 AAC 以外のオーディオが来た場合の処理が未実装
 	 */
 
 	char filename[PATH_MAX];
@@ -1887,10 +2042,11 @@
 	char suffix_v[] = "m2v";
 	filename[0] = '\0';
 
-	if ( av_flag == 1 ) {
+	/* ちょっとこの辺のコードイケてないので後から直すかも */
+	if ( av_flag == TSS_STREAM_TYPE_VIDEO ) {
 		suffix = suffix_v;
 		av_nb = sp->program[sid].video_nb -1;
-	} else if ( av_flag == 2 ){
+	} else if ( av_flag ==  TSS_STREAM_TYPE_AUDIO ){
 		suffix = suffix_a;
 		av_nb = sp->program[sid].audio_nb -1;
 	} else {
@@ -1900,7 +2056,7 @@
 	size = strlen(sp->filename);
 
 	if ( size +16 < sizeof(filename) ) {
-		snprintf(filename, sizeof(filename), "%s_%04d_%02d.%s", sp->filename, sid, av_nb, suffix);
+		snprintf(filename, sizeof(filename), "%s_%05d_%02d.%s", sp->filename, sid, av_nb, suffix);
 		filename[PATH_MAX-1] = '\0';
 	} else {
 		/* ファイル名つけられなくて困るでござるの巻 */
@@ -1908,8 +2064,70 @@
 	}
 	umask(0133);
 	if ( !(sp->esbuf[pid]->fd = open(filename, O_CREAT|O_APPEND|O_RDWR, 00644)) ) {
-		fprintf("cannot open es out file. file[%s].\n", filename);
+		fprintf(stderr, "cannot open es out file. file[%s].\n", filename);
 		return -1;
 	}
 	return 0;
 }
+
+static time_t cue2time(char *yyyymmddhhmiss)
+{
+	struct tm cue_tm;
+	time_t cue_time;
+	char *p;
+	int i, j;
+	char str_yyyy[5];
+	char str_mm[3];
+	char str_dd[3];
+	char str_hh[3];
+	char str_mi[3];
+	char str_ss[3];
+	str_yyyy[0] = '\0';
+	str_mm[0] = '\0';
+	str_dd[0] = '\0';
+	str_hh[0] = '\0';
+	str_mi[0] = '\0';
+	str_ss[0] = '\0';
+
+	p = yyyymmddhhmiss;
+	i = strlen(p); 
+	j = strspn(p, LIST_DECIMAL);
+	if ( i != j && i != 14 ) {
+		/* 数字以外混ぜるな */
+		return -1;
+	}
+	strncpy(str_yyyy, yyyymmddhhmiss, 4);
+	strncpy(str_mm, yyyymmddhhmiss+4, 2);
+	strncpy(str_dd, yyyymmddhhmiss+6, 2);
+	strncpy(str_hh, yyyymmddhhmiss+8, 2);
+	strncpy(str_mi, yyyymmddhhmiss+10, 2);
+	strncpy(str_ss, yyyymmddhhmiss+12, 2);
+	str_yyyy[4] = '\0';
+	str_mm[2] = '\0';
+	str_dd[2] = '\0';
+	str_hh[2] = '\0';
+	str_mi[2] = '\0';
+	str_ss[2] = '\0';
+
+	cue_tm.tm_sec = atoi(str_ss);
+	cue_tm.tm_min = atoi(str_mi);
+	cue_tm.tm_hour = atoi(str_hh);
+	cue_tm.tm_mday = atoi(str_dd);
+	cue_tm.tm_mon = atoi(str_mm)-1;
+	cue_tm.tm_year = atoi(str_yyyy)-1900;
+	cue_tm.tm_isdst = -1;
+	cue_time = mktime(&cue_tm);
+	return cue_time;
+}
+
+/* PCR の PID を検索する */
+static int search_pcr_pid(splitter *sp, int pid)
+{
+	int i;
+	for ( i=0; i < MAX_SERVICES; i++ ) {
+		if ( sp->pcr[i].pid == pid ) {
+			return i;
+		}
+	}
+	return -1;
+}
--- a/recpt1/tssplitter_lite.h	Thu Apr 29 02:02:42 2010 +0900
+++ b/recpt1/tssplitter_lite.h	Wed May 05 20:43:43 2010 +0900
@@ -119,13 +119,14 @@
 typedef struct _program_t
 {
 	int64_t stc;
-	int64_t cue_time;	/* 録画開始時刻 */
+	int64_t cue;		/* 録画開始時刻 */
 	int pmt_packet_id;	/* 該当Program(Service ID)に対応するPMT */
 	int pmt_version;	/* 該当Program(Service ID)に対応するPMTのVersion */
 	int pcr_packet_id;	/* 該当Program(Service ID)のPCRを保持するPID */
 	int64_t pcr1;	/* PCR1 */
 	int64_t pcr2;	/* PCR2 */
-	int packet_nb;	/* PCR計算用カウンタ */
+	int pcr_packet_nb;	/* 直前のPCRを受信したときのパケット数 */
+	int packet_nb;	/* 直前のProgramの処理を実施したときのパケット数 */
 	int64_t pcr_incr;	/* 該当Program(Service ID)に於いて、1つのTSパケットを処理した時に経過する(と想定する時間) */
 	int video_start;		/* VODEO0を蓄積開始している? */
 	int64_t video_pts;		/* 最後に処理したVODEO0のESのPTS */
@@ -133,8 +134,6 @@
 	int audio_nb;			/* PMT に存在する音声ストリームの数 */
 	int video[MAX_VIDEO];	/* PS出力する場合に使うかも */
 	int audio[MAX_AUDIO];	/* PS出力する場合に使うかも */
-	//splitpesbuf_t *pesbuf;
-	//splitesbuf_t *esbuf;
 } program_t;
 /*
  * program_t をサービスID分準備して、使用するイメージでいたけど、
@@ -146,11 +145,10 @@
 typedef struct _splitpesbuf_t
 {
 	program_t *Program;
-	int random_access_indicator; /* TS の random_access_indicator */
 	int64_t pts;
 	int64_t dts;
     int size;
-    u_char buffer[3*1024*1024];
+    u_char buffer[128*1024];
 } splitpesbuf_t;
 
 typedef struct _splitesbuf_t
@@ -165,12 +163,28 @@
     u_char buffer[3*1024*1024];
 } splitesbuf_t;
 
+/* PCR 共有用構造体 */
+typedef struct _pcr_t
+{
+	int pid;
+	int sid_nb; /* PCRを参照しているServiceID(ProgramID)の数 */
+	int sid[MAX_SERVICES];
+} pcr_t;
+
+
 /**
  * splitter構造体
  */
 typedef struct splitter {
+	char *filename; /* ファイル名を上位からもらってくるためのポインタ */
+	char *arg_cue; /* 引数で取得してきた録画開始時刻(HHMISS) */
+	int esout; /* ES出力する? */
 	unsigned char	pids[MAX_PID];
 	unsigned char	pmt_pids[MAX_PID];
+	uint8_t			cat_pids[MAX_PID];
+	uint8_t			pcr_pids[MAX_PID]; /* PCRは複数ServiceID(ProgramID)で共有される */
+	pcr_t			pcr[MAX_SERVICES];
+	int				pcr_nb;
 	unsigned char*	pat;
 	char**			sid_list;
 	unsigned char	pat_count;
@@ -178,17 +192,13 @@
 	int pmt_counter;
 	int avail_pmts[MAX_SERVICES];
 	int num_pmts;
-//	struct timespec tot_offset;
-//	struct timespec STC_timespec;
-	int64_t stc;
-	int64_t cue_time;
-	int status;
 	splitpesbuf_t *pesbuf[MAX_PID];
 	splitesbuf_t *esbuf[MAX_PID];
 	program_t *program;
 	int pid_sid_table[MAX_PID]; /* pid to sid の変換を行うためのテーブル */
-	char *filename; /* ファイル名を上位からもらってくるためのポインタ */
-	int esout; /* ES出力する? */
+	time_t time_cue;
+	time_t time_tot;
+	int tot_packet_nb; /* TOT受信時のパケット受信数 */
 } splitter;
 
 /* b25 decoder would hoard up large chank */
@@ -198,7 +208,7 @@
     u_char buffer[1024*1024];
 } splitbuf_t;
 
-splitter* split_startup(char *sid, char *filename);
+splitter* split_startup(char *sid, char *filename, char *cue_time);
 int split_select(splitter *sp, ARIB_STD_B25_BUFFER *sbuf);
 void split_shutdown(splitter *sp);
 int split_ts(splitter *splitter, ARIB_STD_B25_BUFFER *sbuf, splitbuf_t *dbuf);