Mercurial > pt1.oyama
changeset 183:27e5f99f8991
Delete ES out function. Merge Yazawa's tssplitter_lite. Add liner option.
author | Naoya OYAMA <naoya.oyama@gmail.com> |
---|---|
date | Mon, 05 May 2014 22:08:21 +0900 |
parents | 13f0666bd088 |
children | dc0d3addfd18 |
files | src/Makefile src/http.c src/recpt1.c src/tssplitter_lite.c src/tssplitter_lite.h |
diffstat | 5 files changed, 240 insertions(+), 1743 deletions(-) [+] |
line wrap: on
line diff
--- a/src/Makefile Mon May 05 21:59:36 2014 +0900 +++ b/src/Makefile Mon May 05 22:08:21 2014 +0900 @@ -88,7 +88,7 @@ $(CC) -c $(CFLAGS) -g $(OPTFLAGS) -o $@ $< $(PROG): $(OBJS) - $(CC) $(OBJS) $(LDFLAGS) $(EXTRALIBS) -o $@ + $(CC) $(OBJS) $(LDFLAGS) -lpthread -lupnp -lixml -ldlna $(EXTRALIBS) -o $@ $(PROG2): $(OBJS2) $(CC) $(OBJS2) $(LDFLAGS) $(EXTRALIBS) $(LIBS2) -o $@
--- a/src/http.c Mon May 05 21:59:36 2014 +0900 +++ b/src/http.c Mon May 05 22:08:21 2014 +0900 @@ -612,39 +612,9 @@ http_close }; -// TS_BITRATE$B$O$d$C$D$1;E;v2a$.$k5$$,$7$^$9(B -#define TS_BITRATE (10*1000*1000/8) #define MAX_STREAMING ((off_t)100*1000*1000*1000) static off_t get_streaming_length (void) { - off_t length = 0; - extern thread_data *gp_tdata; - thread_data *tdata = gp_tdata; - time_t cur_time; - struct timespec cur; - struct timespec diff; - clock_gettime(CLOCK_REALTIME, &cur); - off_t bitrate = 0; - - if ( tdata->indefinite ) { - return MAX_STREAMING; - } - diff.tv_nsec = cur.tv_nsec - tdata->streamer->start.tv_nsec; - diff.tv_sec = cur.tv_sec - tdata->streamer->start.tv_sec; - - if ( diff.tv_sec < 1 ) { - bitrate = TS_BITRATE; - } else { - bitrate = (((off_t)tdata->streamer->total_byte)*1e9) / - ( (((off_t)diff.tv_sec)*1e9) + diff.tv_nsec); - } - - time(&cur_time); - length = (tdata->start_time +tdata->recsec -cur_time) * bitrate; - if ( length < 0 ) { - length = 0; - } - length = length - (length % LENGTH_PACKET); - return length; + return MAX_STREAMING; }
--- a/src/recpt1.c Mon May 05 21:59:36 2014 +0900 +++ b/src/recpt1.c Mon May 05 22:08:21 2014 +0900 @@ -203,7 +203,7 @@ // $BJ*M}%A%c%s%M%kJQ99;~$K$O(B splitter $B$O6/@)E*$K:F5/F0$5$;$k(B pthread_mutex_lock(&tdata->splitter_mutex); split_shutdown(splitter); - splitter = split_startup(sid_list, NULL, NULL); + splitter = split_startup(sid_list); if (splitter->sid_list == NULL) { fprintf (stderr, "reader_func() splitter RESTART FAILED.\n"); tdata->splitter = NULL; @@ -547,7 +547,7 @@ struct sockaddr_in *addr = NULL; BUFSZ *qbuf; ARIB_STD_B25_BUFFER *eqbuf; - splitbuf_t splitbuf; + static splitbuf_t splitbuf; ARIB_STD_B25_BUFFER sbuf, dbuf, buf; int code; @@ -556,9 +556,6 @@ buf.size = 0; buf.data = NULL; - splitbuf.size = 0; - splitbuf.buffer_length = 0; - splitbuf.buffer = NULL; if(wfd == -1) fileless = TRUE; @@ -594,15 +591,15 @@ if(use_splitter) { pthread_mutex_lock(&data->splitter_mutex); - splitbuf.size = 0; - if(splitbuf.buffer_length < buf.size && buf.size > 0) { + splitbuf.buffer_filled = 0; + /* allocate split buffer */ + if(splitbuf.buffer_size < buf.size && buf.size > 0) { splitbuf.buffer = realloc(splitbuf.buffer, buf.size); - if(NULL == splitbuf.buffer) { - fprintf(stderr, "splitbuf.buffer realloc failed\n"); + if(splitbuf.buffer == NULL) { + fprintf(stderr, "split buffer allocation failed\n"); use_splitter = FALSE; goto fin; } - splitbuf.buffer_length = buf.size; } while(buf.size) { @@ -631,15 +628,17 @@ } /* $BJ,N%BP>]0J30$r$U$k$$Mn$H$9(B */ code = split_ts(data->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; - } + } break; } /* while */ - buf.size = splitbuf.size; + buf.size = splitbuf.buffer_size; buf.data = splitbuf.buffer; fin: pthread_mutex_unlock(&data->splitter_mutex); @@ -736,12 +735,16 @@ if(use_splitter) { /* $BJ,N%BP>]0J30$r$U$k$$Mn$H$9(B */ code = split_ts(data->splitter, &buf, &splitbuf); - if(code != TSS_SUCCESS) { + if(code == TSS_NULL) { + data->splitter->split_select_finish = TSS_ERROR; + fprintf(stderr, "PMT reading..\n"); + } + else if(code != TSS_SUCCESS) { + fprintf(stderr, "split_ts failed\n"); break; } - buf.data = splitbuf.buffer; - buf.size = splitbuf.size; + buf.size = splitbuf.buffer_size; } if(!fileless && !file_err) { @@ -764,7 +767,7 @@ if(use_splitter) { free(splitbuf.buffer); splitbuf.buffer = NULL; - splitbuf.buffer_length = 0; + //splitbuf.buffer_length = 0; } break; @@ -1263,7 +1266,7 @@ } /* initialize splitter */ if(use_splitter) { - splitter = split_startup(sid_list, es_name_prefix, start_time); + splitter = split_startup(sid_list); if(splitter->sid_list == NULL) { fprintf(stderr, "Cannot start TS splitter\n"); return 1;
--- a/src/tssplitter_lite.c Mon May 05 21:59:36 2014 +0900 +++ b/src/tssplitter_lite.c Mon May 05 22:08:21 2014 +0900 @@ -25,86 +25,18 @@ #include <fcntl.h> #include <sys/stat.h> -#include <math.h> -#include <time.h> #include "decoder.h" #include "recpt1.h" #include "tssplitter_lite.h" -#include "ushare.h" -#include "metadata.h" - -#ifndef AV_RB32 -#define AV_RB32(x) ((((const uint8_t*)(x))[0] << 24) | \ - (((const uint8_t*)(x))[1] << 16) | \ - (((const uint8_t*)(x))[2] << 8) | \ - ((const uint8_t*)(x))[3]) -#endif - -#ifndef AV_RB24 -#define AV_RB24(x) ((((const uint8_t*)(x))[0] << 16) | \ - (((const uint8_t*)(x))[1] << 8) | \ - ((const uint8_t*)(x))[2]) -#endif - -#ifndef AV_RB16 -#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) - -//global -extern struct ushare_t *ut; /* prototypes */ static int ReadTs(splitter *sp, ARIB_STD_B25_BUFFER *sbuf); 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, const uint8_t *buf, int sid, const int size); +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); -static int parse_tot( const unsigned char* packet, time_t *t ); -//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); -//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); -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, 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 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); -static int get_adif_id(uint8_t *p); -static int get_adif_layer(uint8_t *p); -static int get_adif_protection_absent(uint8_t *p); -static int get_adif_profile(uint8_t *p); -static int get_adif_sampling_frequency_index(uint8_t *p); -static int get_adif_private_bit(uint8_t *p); -static int get_adif_channel_configuration(uint8_t *p); -static int get_adif_original_copy(uint8_t *p); -static int get_adif_home(uint8_t *p); -static int get_adif_copyright_idication_bit(uint8_t *p); -static int get_adif_copyright_idication_start(uint8_t *p); -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_gop_start_code(splitesbuf_t *esbuf); -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解析 @@ -194,7 +126,7 @@ #if 0 for(i=0; sid_list[i] != NULL; i++) { - printf(stderr, "sid_list[%d]=[%s].\n",i, sid_list[i]); + printf("sid_list[%d]=[%s].\n",i, sid_list[i]); } #endif return sid_list; @@ -204,30 +136,18 @@ * 初期化処理 */ splitter* split_startup( - char *sid, // [in] サービスID(引数で指定した文字列) - char *filename, // [in] 出力ESファイル名(引数で指定したファイル名) - char *arg_cue // [in] 録画開始時刻(引数で指定した文字列 YYYYMMDDHHMISS) + char *sid // [in] サービスID(引数で指定した文字列) ) { splitter* sp; - int i; sp = malloc(sizeof(splitter)); if ( sp == NULL ) { fprintf(stderr, "split_startup malloc error.\n"); return NULL; } - sp->program = malloc( sizeof(program_t) * MAX_SERVICE_ID ); - if ( sp->program == NULL ) - { - fprintf(stderr, "split_startup malloc error.\n"); - return NULL; - } 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; @@ -240,31 +160,12 @@ sp->pat_count = 0xFF; sp->pmt_retain = -1; sp->pmt_counter = 0; - 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 = NULL; - sp->esout = 0; - if ( filename != NULL ) { - sp->esout = 1; - sp->filename = filename; - } - if ( arg_cue != NULL ) { - sp->arg_cue = arg_cue; - } else { - sp->arg_cue = "00000000000000"; /* とりあえず最小値 */ - } + + memset(sp->section_remain, 0U, sizeof(sp->section_remain)); + memset(sp->packet_seq, 0U, sizeof(sp->packet_seq)); + sp->split_select_finish = TSS_ERROR; + return sp; } @@ -288,13 +189,7 @@ */ void split_shutdown(splitter* sp) { - int i = 0; if ( sp != NULL ) { - if ( sp->program != NULL ) - { - free(sp->program); - sp->program = NULL; - } if ( sp->pat != NULL ) { free(sp->pat); @@ -305,20 +200,6 @@ 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; } @@ -330,24 +211,29 @@ * 対象のチャンネル番号のみの PAT の再構築と出力対象 PID の抽出を行う */ 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の数 +#endif { -#if 0 - splitter *sp, // [in/out] splitter構造体 - ARIB_STD_B25_BUFFER *sbuf, // [in] pt1_drvの入力TS -#endif - int length = sbuf->size; int pid; int result = TSS_ERROR; int index; + int analyze_result = 0; index = 0; while(length - index - LENGTH_PACKET > 0) { pid = GetPid(sbuf->data + index + 1); // PAT - if(PAT == pid) { + if(0x0000 == pid) { result = AnalyzePat(sp, sbuf->data + index); - if(TSS_SUCCESS != result) { + if(result != TSS_SUCCESS) { /* 下位の関数内部でmalloc error発生 */ return result; } @@ -358,11 +244,16 @@ * 残すべきPCR/AUDIO/VIDEO PIDを取得する */ if(sp->pmt_pids[pid] == 1) { /* この中にはPMT毎に一度しか入らないようにしておく */ - sp->pmt_pids[pid]++; - sp->pmt_counter += 1; - DemuxTs(sbuf->data +index, sp, pid); /* AnalyzePmt より DemuxTs の方がアダプテーションフィールドの処理が良いので変更 */ + 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; + } } - /* 録画する全てのPMTについて、中にあるPCR/AUDIO/VIDEOのPIDを得る */ + /* 録画する全てのPMTについて、中にあるPCR/AUDIO/VIDEOのPIDを + * 得る */ /* pmt_counter と pmt_retain が一致する場合に条件は満たされる */ if(sp->pmt_counter == sp->pmt_retain) { result = TSS_SUCCESS; @@ -377,29 +268,56 @@ 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 分離処理 */ int split_ts( - splitter *sp, // [in] splitterパラメータ + splitter *splitter, // [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_h = 0; - int pcr_l = 0; - int ret = 0; - int sid = 0; - program_t *program; - static int packet_nb; /* パケット受信数 */ - int i = 0; + int result = TSS_SUCCESS; + int pmts = 0; + int version = 0; /* 初期化 */ - dbuf->size = 0; + dbuf->buffer_filled = 0; if (sbuf->size < 0) { return TSS_ERROR; } @@ -409,160 +327,63 @@ while(sbuf->size > s_offset) { pid = GetPid(sptr + s_offset + 1); - sid = sp->pid_sid_table[pid]; /* PIDからSIDを取得 */ switch(pid) { // PAT - case PAT: + case 0x0000: // 巡回カウンタカウントアップ - if(0xFF == sp->pat_count) { - sp->pat_count = sp->pat[3]; + if(0xFF == splitter->pat_count) { + splitter->pat_count = splitter->pat[3]; } else { - sp->pat_count += 1; - if(0 == sp->pat_count % 0x10) { - sp->pat_count -= 0x10; + splitter->pat_count += 1; + if(0 == splitter->pat_count % 0x10) { + splitter->pat_count -= 0x10; } } - sp->pat[3] = sp->pat_count; + splitter->pat[3] = splitter->pat_count; - memcpy(dptr + d_offset, sp->pat, LENGTH_PACKET); + memcpy(dptr + d_offset, splitter->pat, LENGTH_PACKET); d_offset += LENGTH_PACKET; - dbuf->size += LENGTH_PACKET; - break; - case TOT: - /* TOT に TDTの情報全てが含まれており、実放送では TOT しか送信されない */ - /* TOT は 500msec の誤差が保証されている - * 閏秒の場合は最大1.5秒の誤差となる - */ - 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; - } + dbuf->buffer_filled += LENGTH_PACKET; break; default: - /* ■時間管理に関しての実装方針■ */ - /* - * ■時間関係を扱っている変数■ - * 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と同じ方針) - * - * ■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 ( 2 == sp->pmt_pids[pid] ) { - /* PMT の追跡 */ - DemuxTs((sptr+s_offset), sp, pid); + 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 == 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; - fprintf(stderr, "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 ) { -// fprintf(stderr, "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); - fprintf(stderr, "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); - fprintf(stderr, "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]); - fprintf("STC[%llu] SID[%d]\n", program->stc, sid); - } -#endif - /* TS処理 */ - DemuxTs((sptr+s_offset), sp, pid); + if(0 != splitter->pids[pid]) { memcpy(dptr + d_offset, sptr + s_offset, LENGTH_PACKET); d_offset += LENGTH_PACKET; - dbuf->size += LENGTH_PACKET; + dbuf->buffer_filled += LENGTH_PACKET; } break; } /* switch */ + s_offset += LENGTH_PACKET; - packet_nb += 1; /* パケット受信数加算 */ } - return(TSS_SUCCESS); + + return result; } /** @@ -572,13 +393,14 @@ */ static int AnalyzePat(splitter *sp, unsigned char *buf) #if 0 + splitter *sp + unsigned char** pat, // [out] PAT 情報(再構築後) + unsigned char* pids, // [out] 出力対象 PID 情報 + char** sid_list, // [in] 出力対象サービス ID のリスト + unsigned char* pmt_pids, // [out] サービス ID に対応する PMT の PID + int* pmt_retain // [out] 残すPMTの数 + unsigned char* buf, // [in] 読み込んだバッファ - unsigned char** pat, // [out] PAT 情報(再構築後) - unsigned char* pids, // [out] 出力対象 PID 情報 - char** sid_list, // [in] 出力対象サービス ID のリスト - unsigned char* pmt_pids, // [out] サービス ID に対応する PMT の PID - int* pmt_retain // [out] 残すPMTの数 -) #endif { int pos[MAX_PID]; @@ -607,10 +429,12 @@ /* prescan SID/PMT */ for(i = 13, j = 0; i < (size + 8) - 4; i = i + 4) { + pid = GetPid(&buf[i+2]); - if(pid == NIT) + if(pid == 0x0010) continue; - avail_sids[j] = (buf[i] << 8) + buf[i+2]; + + avail_sids[j] = (buf[i] << 8) + buf[i+1]; sp->avail_pmts[j] = pid; j++; } @@ -620,8 +444,9 @@ /* size + 8 = パケット全長 */ /* 最終 4 バイトはCRCなので飛ばす */ for(i = 13; i < (size + 8) - 4; i = i + 4) { + pid = GetPid(&buf[i+2]); - if(pid == NIT) + if(pid == 0x0010) continue; service_id = (buf[i] << 8) + buf[i+1]; @@ -631,15 +456,13 @@ 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; pos[pid] = i; sid_found = TRUE; + sp->pmt_version[sp->pmt_retain].pid = pid; sp->pmt_retain += 1; - sp->program[service_id].pmt_packet_id = pid; - sp->pid_sid_table[pid] = service_id; sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id); p++; continue; @@ -652,9 +475,8 @@ *(pids+pid) = 1; pos[pid] = i; sid_found = TRUE; + sp->pmt_version[sp->pmt_retain].pid = pid; sp->pmt_retain += 1; - sp->program[service_id].pmt_packet_id = pid; - sp->pid_sid_table[pid] = service_id; sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id); } p++; @@ -668,9 +490,8 @@ *(pids+pid) = 1; pos[pid] = i; sid_found = TRUE; + sp->pmt_version[sp->pmt_retain].pid = pid; sp->pmt_retain += 1; - sp->program[service_id].pmt_packet_id = pid; - sp->pid_sid_table[pid] = service_id; sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id); } p++; @@ -684,9 +505,8 @@ *(pids+pid) = 1; pos[pid] = i; sid_found = TRUE; + sp->pmt_version[sp->pmt_retain].pid = pid; sp->pmt_retain += 1; - sp->program[service_id].pmt_packet_id = pid; - sp->pid_sid_table[pid] = service_id; sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id); } p++; @@ -700,9 +520,8 @@ *(pids+pid) = 1; pos[pid] = i; sid_found = TRUE; + sp->pmt_version[sp->pmt_retain].pid = pid; sp->pmt_retain += 1; - sp->program[service_id].pmt_packet_id = pid; - sp->pid_sid_table[pid] = service_id; sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id); } p++; @@ -715,12 +534,20 @@ *(pids+pid) = 1; pos[pid] = i; sid_found = TRUE; + sp->pmt_version[sp->pmt_retain].pid = pid; sp->pmt_retain += 1; - sp->program[service_id].pmt_packet_id = pid; - sp->pid_sid_table[pid] = service_id; sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id); break; } + else if(!strcasecmp(*p, "epg")) { + /* epg抽出に必要なPIDのみを保存する */ + sid_found = TRUE; + *(pids+0x11) = 1; + *(pids+0x12) = 1; + *(pids+0x26) = 1; + *(pids+0x27) = 1; + break; + } p++; } /* while */ @@ -728,16 +555,20 @@ /* if sid has been specified but no sid found, fall back to all */ if(*sid_list && !sid_found) { - for(i = 17; i < (size + 8) - 4; i = i + 4) { + for(i = 13; i < (size + 8) - 4; i = i + 4) { + + pid = GetPid(&buf[i+2]); + if(pid==0x0010) + continue; + service_id = (buf[i] << 8) + buf[i+1]; pid = GetPid(&buf[i + 2]); *(pmt_pids+pid) = 1; *(pids+pid) = 1; pos[pid] = i; sid_found = TRUE; + sp->pmt_version[sp->pmt_retain].pid = pid; sp->pmt_retain += 1; - sp->program[service_id].pmt_packet_id = pid; - sp->pid_sid_table[pid] = service_id; sprintf(chosen_sid, "%s %d", *chosen_sid ? chosen_sid : "", service_id); } } @@ -749,7 +580,7 @@ fprintf(stderr, "\n"); fprintf(stderr, "Chosen sid =%s\n", chosen_sid); -#if 0 +#if 1 /* print PMTs */ fprintf(stderr, "Available PMT = "); for(k=0; k < sp->num_pmts; k++) @@ -776,8 +607,7 @@ */ static int RecreatePat(splitter *sp, unsigned char *buf, int *pos) #if 0 - splitter *sp // [in/out] splitter - unsigned char* buf, // [in] 読み込んだバッファ + splitter *sp // [in/out] int *pos // [in] 取得対象 PMT のバッファ中の位置 #endif { @@ -795,11 +625,13 @@ { y[i] = buf[i + 5]; } + // NIT y[LENGTH_PAT_HEADER-4] = 0x00; y[LENGTH_PAT_HEADER-3] = 0x00; y[LENGTH_PAT_HEADER-2] = 0xe0; y[LENGTH_PAT_HEADER-1] = 0x10; + // チャンネルによって変わる部分 for (i = 0; i < MAX_PID; i++) { @@ -844,224 +676,95 @@ return(TSS_SUCCESS); } - /** * PMT 解析処理 * * PMT を解析し、保存対象の PID を特定する - * TSヘッダとアダプテーションフィールドの処理は DemuxTs に一任するので、 - * この内部では、セクションデータの先頭ポインタをもらってくる */ -static int AnalyzePmt(splitter *sp, const uint8_t *buf, int sid, const int size) +static int AnalyzePmt(splitter *sp, unsigned char *buf, unsigned char mark) #if 0 - unsigned char* buf, // [in] セクション先頭 - unsigned char* pids) // [out] 出力対象 PID 情報 + unsigned char* buf, // [in] 読み込んだバッファ + unsigned char* pids // [out] 出力対象 PID 情報 #endif { unsigned char Nall; unsigned char N; 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 + int pid; + int retry_count = 0; + int count; + int payload_offset; // offset to payload -// 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; + pid = GetPid(&buf[1]); + if (buf[1] & 0x40) { // PES開始インジケータ + sp->section_remain[pid] = ((buf[6] & 0x0F) << 8) + buf[7] + 3; // セクションサイズ取得(ヘッダ込) + payload_offset = 5; - /* get version */ - sp->program[sid].pmt_version = get_pmt_version(buf); -#ifdef PmtDebug - printf(" pmt_version[%02x]\n", sp->program[sid].pmt_version); -#endif + for (count = 0; sp->pmt_retain > count; count++) { + if (sp->pmt_version[count].pid == pid) { + sp->pmt_version[count].version = buf[10] & 0x3e; + } + } + // PCR, 番組情報が先頭からはみ出ることはないだろう - // 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 + 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; - /* 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; - } + while(p < N) { + uint32_t ca_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; + sp->pids[ca_pid] = mark; } - 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; + p += len; } } - - 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; + 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; } -#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; + 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; - 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 - fprintf(stderr, " 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 - * 0x00 ITU-T | ISO/IEC Reserved - * 0x01 ISO/IEC 11172 Video - * 0x02 ITU-T Rec. H.262 | ISO/IEC 13818-2 Video or ISO/IEC 11172-2 constrained parameter video stream - * 0x03 ISO/IEC 11172 Audio - * 0x04 ISO/IEC 13818-3 Audio - * 0x05 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 private_sections - * 0x06 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 PES packets containing private data - * 0x07 ISO/IEC 13522 MHEG - * 0x08 ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Annex A DSM-CC - * 0x09 ITU-T Rec. H.222.1 - * 0x0A ISO/IEC 13818-6 type A - * 0x0B ISO/IEC 13818-6 type B - * 0x0C ISO/IEC 13818-6 type C - * 0x0D ISO/IEC 13818-6 type D - * 0x0E ITU-T Rec. H.222.0 | ISO/IEC 13818-1 auxiliary - * 0x0F ISO/IEC 13818-7 Audio with ADTS transport syntax - * 0x10 ISO/IEC 14496-2 Visual - * 0x11 ISO/IEC 14496-3 Audio with the LATM transport syntax as defined in ISO/IEC 14496-3 / AMD 1 - * 0x12 ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in PES packets - * 0x13 ISO/IEC 14496-1 SL-packetized stream or FlexMux stream carried in ISO/IEC14496_sections. - * 0x14 ISO/IEC 13818-6 Synchronized Download Protocol - * 0x15-0x7F ITU-T Rec. H.222.0 | ISO/IEC 13818-1 Reserved - * 0x80-0xFF User Private - * - */ + Nall = sp->section_remain[pid]; + if(Nall > LENGTH_PACKET - payload_offset) + Nall = LENGTH_PACKET - payload_offset; // ES PID - while (N < Nall + 8 - 4) { - av_flag = 0; + while (N <= Nall + payload_offset - 5) + { // ストリーム種別が 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 = TSS_STREAM_TYPE_VIDEO; -#ifdef PmtDebug - fprintf(stderr, " 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 = TSS_STREAM_TYPE_AUDIO; -#ifdef PmtDebug - fprintf(stderr, " AUDIO PacketID[%d][0x%04x] StreamType[0x%02x]\n", epid, epid, buf[N]); -#endif - } else { -#ifdef PmtDebug - fprintf (stderr, " OTHER PacketID[%d][0x%04x] StreamType[0x%02x]\n", epid, epid, buf[N]); -#endif - ; /* A/V どちらでもないものはとりあえずスルー */ - } - if ( av_flag && sp->esout ) { - /* ESバッファはNULLか? */ - if ( sp->esbuf[epid] == NULL ) { - sp->esbuf[epid] = malloc(sizeof(splitesbuf_t)); - if ( sp->esbuf[epid] == NULL ) { - fprintf(stderr, "malloc error\n"); - return TSS_NULL; - } - sp->esbuf[epid]->size = 0; - sp->esbuf[epid]->Program = &(sp->program[sid]); - sp->esbuf[epid]->fd = -1; - if ( creat_es_file(sp, sid, epid, av_flag) ) { - return TSS_ERROR; - } - } - /* PESバッファはNULLか? */ - if ( sp->pesbuf[epid] == NULL ) { - sp->pesbuf[epid] = malloc(sizeof(splitpesbuf_t)); - if ( sp->pesbuf[epid] == NULL ) { - fprintf(stderr, "malloc error\n"); - return TSS_NULL; - } - sp->pesbuf[epid]->size = 0; - sp->pesbuf[epid]->Program = &(sp->program[sid]); - } - } + sp->pids[epid] = mark; + } + N += 4 + (((buf[N + 3]) & 0x0F) << 8) + buf[N + 4] + 1; + retry_count++; + if(retry_count > Nall) { + return TSS_ERROR; } -// 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; + sp->section_remain[pid] -= Nall; + + if (sp->section_remain[pid] > 0) + return SECTION_CONTINUE; + else + return TSS_SUCCESS; } /** @@ -1084,22 +787,17 @@ for (j = 0; j < 8; j++) { - bit = (x >> (7 - j)) & 0x1; - c = 0; if (crc & 0x80000000) { c = 1; } - crc = crc << 1; - if (c ^ bit) { crc ^= 0x04C11DB7; } - crc &= 0xFFFFFFFF; } } @@ -1115,1037 +813,3 @@ { return ((data[0] & 0x1F) << 8) + data[1]; } - -/* return the 90kHz PCR and the extension for the 27MHz PCR. return - (-1) if not available */ -static int parse_pcr(int64_t *ppcr_high, int *ppcr_low, - const uint8_t *packet) -{ - int afc, len, flags; - const uint8_t *p; - unsigned int v; - - afc = (packet[3] >> 4) & 3; - if (afc <= 1) - return -1; - p = packet + 4; - len = p[0]; - p++; - if (len == 0) - return -1; - flags = *p++; - len--; - if (!(flags & 0x10)) - return -1; - if (len < 6) - return -1; - v = AV_RB32(p); - *ppcr_high = ((int64_t)v << 1) | (p[4] >> 7); - *ppcr_low = ((p[4] & 1) << 8) | p[5]; - return 0; -} - -/* pesbufが空か判定 (ret. 0:not empty / 1: empty) */ -static int pesbuf_empty(splitpesbuf_t *pesbuf){ - return pesbuf->size == 0; -} - -/* pesbufをクリア */ -void pesbuf_clear(splitpesbuf_t *pesbuf){ - pesbuf->size = 0; -} - -/* 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){ - return -1; - } - memcpy(pesbuf->buffer +pesbuf->size, data, len); - pesbuf->size += len; - return 0; -} - -/* pesbufから、PESの先頭(packet_start_code_prefix)を探す */ -/* (ret. >=0:offset / -1: error) */ -static int pesbuf_packet_start_code_prefix(splitpesbuf_t *pesbuf){ - uint8_t packet_start_code_prefix[3] = {0x00, 0x00, 0x01}; - int i = 0; - - /* 小さすぎる */ - if(pesbuf->size < sizeof packet_start_code_prefix){ - return -1; - } - /* 先頭で探す */ - if(!memcmp(pesbuf->buffer + i, packet_start_code_prefix, sizeof packet_start_code_prefix)){ - return 0; - } - -#if 0 - /* 先頭以外からも探す場合は、ここのコードを有効化する。 */ - /* ただし、MPEG-Videoのstart_codeと同じなので、深追いしない方がいいと思う... */ - for(i = 0; i < pesbuf->size - sizeof packet_start_code_prefix; i++){ - if(!memcmp(pesbuf->buffer + i, packet_start_code_prefix, sizeof packet_start_code_prefix)){ - return i; - } - } -#endif - - return -1; -} - -/** - * TSの解析とDemuxを行う - */ -static int DemuxTs(const uint8_t *packet, splitter *sp, const int pid) -{ - /* - * PES先頭までの長さは - * 4byte : continity counter - * 27,28bit が adaptation fileld制御 - * (01:ペイロードのみ, 10:adaptation fileldのみ、11:adaptation fileld+payload、00:reserved) - * ペイロード長 = 188 - TS header(4byte) -adaptation field長 -1 - */ - /* ありがとう */ - - int payload_offset; /* ペイロードオフセット(=パケット先頭からのバイト数) */ - int payload_length; /* ペイロード長 */ - int pes_started; - int adaptation_field_control; - int payload_unit_start_indicator; -// int random_access_indicator = 0; - int sid = sp->pid_sid_table[pid]; /* SIDをPIDから引いているが、PCRとCATは重複しているので注意*/ - - payload_offset = LENGTH_TS_HEADER; - - if ( sp->pesbuf[pid] == NULL ) { - pes_started = 0; /* malloc走る前(セクション解析だったら呼んで良い) */ - } else { - pes_started = !pesbuf_empty(sp->pesbuf[pid]); /* PES蓄積開始済み */ - } - - /* adaptation_field_controlおよびadaptation_fieldを処理する */ - adaptation_field_control = (packet[3] & 0x30) >> 4; - if ( adaptation_field_control == 0x02 || adaptation_field_control == 0x00) { - /* ペイロードなしの場合 */ - return 0; /* 別にエラーではない */ - } else if ( adaptation_field_control == 0x03 ) { - /* アダプテーションフィールド+ペイロードの場合 */ - if ( packet[LENGTH_TS_HEADER] != 0 ) { -// random_access_indicator = (packet[5] & 0x40) >> 6; - } - /* ペイロード開始位置 = TSヘッダ長 + アダプテーションフィールド長 + 1 */ - payload_offset += packet[LENGTH_TS_HEADER] + 1; - } else { - /* ペイロードのみ */ - ; /* 特に処理なし */ - } - - /* ペイロード長を出す */ - payload_length = LENGTH_PACKET - payload_offset; - if( payload_length <= 0 ){ /* payload長が0以下の場合 */ - return -1; /* エラーにすべきかは微妙なところ */ - } - - /* payload_unit_start_indicatorを処理(1) */ - payload_unit_start_indicator = (packet[1] & 0x40) >> 6; - /* (sectionの場合は、ここでpointer_fieldの処理などを行い、payload_offsetに反映する) */ - if ( sp->pmt_pids[pid] == 2 ) { /* PID が録画対象の PMT であるか? */ - if ( get_pmt_version(packet+payload_offset) != sp->program[sid].pmt_version ) { - /* pmt versionに差分あり */ - fprintf(stderr, "pmt version diff found pmt_pid[%d]" - " old_version[0x%02x]" - " new_version[0x%02x].\n", - pid, - sp->program[sid].pmt_version, - get_pmt_version(packet+payload_offset)); - AnalyzePmt(sp, packet +payload_offset, sid, payload_length); - /* payload 何byte処理したか等管理するべき */ - } - 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蓄積開始を行う */ - if( payload_unit_start_indicator ){ - /* PES開始 */ - if ( pes_started ) { - /* バッファにデータがあればPES終端なので処理してクリア */ -// 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 { - pes_started = 1; - } - } - - /* PES蓄積処理 */ - if ( pes_started ){ - /* PES蓄積開始済み(これからPES蓄積開始を含む)なら、payloadをPESとして追加 */ - pesbuf_add(sp->pesbuf[pid], packet + payload_offset, payload_length); - } - /* おつかれさまでした */ - return 0; -} - -#if 0 -未使用なため削除 -/* PMT_PID から Program(Service ID)を確定させる */ -static int search_pmt_program(splitter *sp, int pid) -{ - /* この関数は大変遅いのでなるべく使用しない */ - int i; - for ( i = 0; i < MAX_SERVICE_ID; i++ ) { - if ( sp->program[i].pmt_packet_id == pid ) { - return i; - } - } - return -1; -} -#endif - -/* esbufが空か判定 (ret. 0:not empty / 1: empty) */ -static int esbuf_empty(splitesbuf_t *esbuf){ - return esbuf->size == 0; -} - -/* esbufをクリア */ -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) */ -static int esbuf_add(splitesbuf_t *esbuf, const uint8_t *data, int len){ - if(esbuf->size + len > sizeof esbuf->buffer){ - return -1; - } - memcpy(esbuf->buffer +esbuf->size, data, len); - esbuf->size += len; - return 0; -} - -/* - * 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 len_pesh = 0; - int code = 0; - int flags = 0; - int len_pes = 0; - int len_pesh_supposed = 0; - int pes_extension_flags = 0; - int pes_extension_flags2 = 0; - int program_packet_sequence_counter_flag = 0; - int es_rate = 0; - const uint8_t *p = pesbuf->buffer; - const uint8_t *p_end = pesbuf->buffer +pesbuf->size; - int original_stuffing_length = 0; - int data_alignment_indicator = false; - int es_started; - int payload_offset = 0; - int payload_length = 0; - int audio_lipsync_offset = 0; - int i = 0; - int64_t audio_pts = 0; - int adts_freq = 0; - int64_t adts_frame_time = 0; - int gop_start = -1; - - /* ありがとう */ - /* ありがとうとコメントを書くと、 - * 動作がよくなる - * バグが減る - * バイナリサイズが小さくなる - * 画質がよくなる - * 音質がよくなる - */ - if ( esbuf == NULL ) { - return -1; /* malloc走る前この関数は呼んじゃダメです */ - } else { - es_started = !esbuf_empty(esbuf); /* ES蓄積開始済み */ - } - - payload_offset = pesbuf_packet_start_code_prefix(pesbuf); - if ( payload_offset == -1 ) { - return -1; - } - p += payload_offset; - /* http://dvd.sourceforge.net/dvdinfo/pes-hdr.html - * - * Stream ID : type : extension present? - * (1011 1101) 0xBD : Private stream 1 (non MPEG audio, subpictures) : YES - * (1011 1110) 0xBE : Padding stream : NO - * (1011 1111) 0xBF : Private stream 2 (navigation data) : NO - * (110x xxxx) 0xC0 - 0xDF : MPEG-1 or MPEG-2 audio stream number x xxxx : YES - * (1110 xxxx) 0xE0 - 0xEF : MPEG-1 or MPEG-2 video stream number xxxx : YES - * note: DVD allows only 8 audio streams/DVD allows only 1 video stream - */ - /* http://www2.arib.or.jp/johomem/pdf/2009/2009_0088.pdf - * - * 0xBC : プログラムストリームマップ - * 0xBD : プライベートストリーム1 - * 0xBE : パディングストリーム - * 0xBF : プライベートストリーム2 - * 0xC0 - 0xDF : ISO/IEC 13318 3、ISO/IEC 11172 3、ISO/IEC 13318 7 or ISO/IEC 14496 3 audio xxxx - * 0xE0 - 0xEF : ITU-T H.262、ISO/IEC 11172 2、ISO/IEC 14496 2 or ITU-T H264映像ストリーム - * 0xF0 : ECMストリーム - * 0xF1 : EMMストリーム - * 0xF2 : ITU-T勧告H.222.0 Annex A 又は ISO/IEC 13318 6 のDSMCCストリーム - * 0xF3 : ISO/IEC 13522ストリーム - * 0xF4 : ITU-T勧告 H.222.1 type A - * 0xF5 : ITU-T勧告 H.222.1 type B - * 0xF6 : ITU-T勧告 H.222.1 type C - * 0xF7 : ITU-T勧告 H.222.1 type D - * 0xF8 : ITU-T勧告 H.222.1 type E - * 0xF9 : 補助ストリーム - * 0xFA : ISO/IEC 14496 1SLパケット化ストリーム - * 0xFB : ISO/IEC 14496 1フレックスマックスストリーム - * 0xFC : メタデータストリーム - * 0xFD : 拡張ストリームID - * 0xFE : 未定義 - * 0xFF : プログラムストリームディレクトリ - */ - /* 上記より、ここでは - * MPEG-1 or MPEG-2 audio stream と - * MPEG-1 or MPEG-2 video stream と - * Private stream 1 と - * 0xFD(拡張ストリームID)を抽出する - * ?0xBF Private stream 2 落としてるけどよいの? - * >多分よくない。ffmpegではここに入る前に PRIVATE_STREAM2 のコードが入っている - */ - code = (p[3] &0xff) | 0x100; - if ( !((code >= 0x1c0 && code <= 0x1df) || - (code >= 0x1e0 && code <= 0x1ef) || - (code == 0x1bd) || (code == 0x1fd))) { - return -1; - } - /* PES のデータ長 */ - /* 動画のストリームである場合には、ES長は不定となるので0が許容される */ - len_pes = AV_RB16(p+4); - /* PESヘッダ拡張部(byte 6) */ - flags = p[6] & 0xff; - if ( flags & 0x04 ) { - data_alignment_indicator = true; - /* data alignment indicator */ - /* video start code or audio syncword. */ - /* おそらくここで区切るとピクチャ単位 */ - //printf("data alignment indicator found pid[%d].\n", pid); - } - flags = p[7] & 0xff; - /* PESヘッダデータ長(byte 8) */ - len_pesh = p[8] & 0xff; - p += LENGTH_PES_HEADER; - payload_offset += LENGTH_PES_HEADER +len_pesh; - if ( p +payload_offset >= p_end ) { - /* PESヘッダ長すぎます */ - return -1; - } - - /* flags - * +---------------------------------------------------+ - * name |byte 7(flags) | - * +-----+-----+-----+------+----------+----+----------+ - * Bit |76 |5 |4 |3 |2 |1 |0 | - * +-----+-----+-----+------+----------+----+----------+ - * field|PTS |ESCR |ES |DSM |additional|PES |PES | - * name |DTS |FLAG |RATE |Trick |copy info |CRC |Extension | - * |flag | |flag |mode |flag |flag|flag | - * +-----+-----+-----+------+----------+----+----------+ - * Data |5,5 |6 |3 |1 |1 |2 |1 |(24) - * byte | | | | | | | | - * +-----+-----+-----+------+----------+----+----------+ - */ - if ( flags & PTS_FLAG ) { - if ( p +LENGTH_PTS >= p_end ) { - return -1; - } - pesbuf->pts = get_pts(p); - p += LENGTH_PTS; - len_pesh_supposed += LENGTH_PTS; - } - if ( flags & DTS_FLAG ) { - if ( p +LENGTH_PTS >= p_end ) { - return -1; - } - pesbuf->dts = get_pts(p); - p += LENGTH_PTS; - len_pesh_supposed += LENGTH_PTS; - } - if ( flags & ESCR_FLAG ) { - p += 6; - len_pesh_supposed += 6; - } - if ( flags & ES_RATE_FLAG ) { - es_rate = AV_RB24(p); - es_rate = (es_rate >>1) & 0x3fffff; - es_rate = es_rate * 50; - fprintf(stderr, "pid[%d] es_rate[%d]Byte/Sec.\n", pid, es_rate); - p += 3; - len_pesh_supposed += 3; - } - if ( flags & DSM_TRICK_MODE_FLAG ) { - p += 1; - len_pesh_supposed += 1; - } - if ( flags & COPY_INFO_FLAG ) { - p += 1; - len_pesh_supposed += 1; - } - if ( flags & CRC_FLAG ) { - p += 2; - len_pesh_supposed += 2; - } - if ( flags & EXTENSION_FLAG ) { - /* PES Extension flag - * +------------------------------------------------------------------+ - * name |PES Extension flag | - * +-----------+-----------+----------------+------+---+--------------+ - * bit |7 |6 |5 |4 |321|0 | - * +-----------+-----------+----------------+------+---+--------------+ - * field|PES private|pack header|program |P-STD |111|PES extension | - * name |data flag |field flag |packet |buffer| |flag2 | - * | | |sequence counter|flag | | | - * +-----------+-----------+----------------+------+---+--------------+ - * Data |16 |1 |2 |2 | |1 |(23) - * byte | | | | | | | - * +-----------+-----------+----------------+------+---+--------------+ - */ - if ( p >= p_end ) { - return -1; - } - pes_extension_flags = *p & 0xff; - p += 1; - len_pesh_supposed += 1; - if ( pes_extension_flags & PES_PRIVATE_DATA_FLAG ) { - p += 16; - len_pesh_supposed += 16; - } - if ( pes_extension_flags & PACK_HEADER_FIELD_FLAG ) { - p += 1; - len_pesh_supposed += 1; - } - if ( pes_extension_flags & PROGRAM_PACKET_SEQUENCE_COUNTER ) { - if ( p >= p_end ) { - return -1; - } - program_packet_sequence_counter_flag = *p & 0xff; - original_stuffing_length = program_packet_sequence_counter_flag & 0x3f; - p += 2; - len_pesh_supposed += 2; - } - if ( pes_extension_flags & PSTD_BUFFER_FLAG ) { - p += 2; - len_pesh_supposed += 2; - } - if ( pes_extension_flags & PES_EXTENSION_FLAG2 ) { - /* PES Extension flag2 - * +------------------------------------------------------------------+ - * name |PES Extension flag2 | - * +------+-----------------------------------------------------------+ - * bit |7 |6543210 | - * +------+-----------------------------------------------------------+ - * field|marker|PES_extension_field_length | - * name |bit | | - * |'1' | | - * +------+-----------------------------------------------------------+ - * Data |- |0 <= N <= 127 |(127) - * byte | | | - * +------+-----------------------------------------------------------+ - */ - if ( p >= p_end ) { - return -1; - } - pes_extension_flags2 = *p & 0x7f; - p += 1; - len_pesh_supposed += 1; - - p += pes_extension_flags2; - 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 ) { /* data_alignment_indicator 区切りでESを出力する */ - if ( es_started ) { /* ES にデータが蓄積されている */ - /* - * ビデオをファイル出力し始める条件(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; - fprintf(stderr, "video stream. pid[%d] v_pts[%llu].\n", pid, esbuf->pts); - } else { - /* 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; - } - } - /* - * オーディオをファイル出力し始める条件(1. 2. を満たすこと) - * 1. 動画の蓄積は開始されている - * 2. 動画のGOPの1番目のIピクチャのPTSとオーディオのPTSを比較して以下のどちらかを満たすこと - * 2.1. 差分が11msec以内(1024*90k/AACのサンプリング周波数) - * 1024 : ADTSデータの1フレームのサンプル数 - * 90k : PTSの周波数 - * 2.2. 過ぎている(過ぎている場合はオーディオESの蓄積の継続と次のGOP狙いにする?) - * #動画よりオーディオ側の方が先にESバッファの蓄積を始めるハズなので気にすること無いかなぁ… - */ - else if ( (is_audio_stream(pid, esbuf) != -1) && !(esbuf->started) ) { - if ( !(esbuf->Program->video_start) ) { - /* - * VIDEO が始まってない場合、 - * ESバッファの余裕がある限り、オーディオをESバッファに蓄積し続ける - */ - if ( esbuf->size + payload_length > sizeof esbuf->buffer ){ - /* 溢れそうになったらクリア */ - esbuf_clear(esbuf, pesbuf->pts, pesbuf->dts); - } - } else if ( esbuf->Program->video_start ) { /* video 蓄積が開始されている?*/ - fprintf(stderr, "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)1024*90000/adts_freq); /* PTSは90KHz */ - /* オーディオをフレーム単位で捨ててPTSを進める */ - while ( (esbuf->Program->video_pts > audio_pts +adts_frame_time/2) ) { - /* オーディオデータを捨てると audio_pts は1フレーム分大きくなる */ - 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; - } - fprintf(stderr, "audio stream drop. pid[%d] pts[%llu].\n", pid, audio_pts); - audio_pts += adts_frame_time; /* AACの1フレーム分、時間を進める */ - } - if ( (esbuf->Program->video_pts <= audio_pts +adts_frame_time/2) ) { - fprintf(stderr, "lipsync start. v_pts[%llu] a_pts[%llu].\n", esbuf->Program->video_pts, audio_pts); - memmove(esbuf->buffer +audio_lipsync_offset, - esbuf->buffer, - esbuf->size -audio_lipsync_offset); - esbuf->size -= audio_lipsync_offset; - esbuf->started = 1; /* オーディオのファイル出力を有効化 */ - } - } else { - ; /* 該当するものは無いはず */ - } - } else { - /* 得に処理なし */ - ; - } - /* バッファをファイルに出力してクリア */ - if ( esbuf->started ) { /* 該当ストリームはファイル出力の有効化をされている? */ - esbuf_write(esbuf); - esbuf_clear(esbuf, pesbuf->pts, pesbuf->dts); - } - } else { - /* ES蓄積を新たに開始 */ - es_started = 1; - esbuf->pts = pesbuf->pts; - esbuf->dts = pesbuf->dts; - } - //} - - /* ES蓄積処理 */ - if ( es_started ) { - /* ES蓄積開始済み(これからES蓄積開始を含む)なら、payloadをESとして追加 */ - esbuf_add(esbuf, pesbuf->buffer +payload_offset, payload_length); - } - /* お疲れさまでした */ - return 0; -} - -/* Program の N 番目の AUDIO STREAM であるかを返却する */ -static int is_audio_stream(const int pid, splitesbuf_t *esbuf) -{ - int i = 0; - program_t* program = esbuf->Program; - while (i < program->audio_nb) - { - if (program->audio[i] == pid) { - return i; - } - i++; - } - return -1; -} - -/* Program の N 番目の VIDEO STREAM であるかを返却する */ -static int is_video_stream(const int pid, splitesbuf_t *esbuf) -{ - int i = 0; - program_t* program = esbuf->Program; - while (i < program->video_nb) - { - if (program->video[i] == pid) { - return i; - } - i++; - } - return -1; -} - -/* - * ESをファイル出力する - * エラーハンドリングしてないね… - */ -static int esbuf_write(splitesbuf_t *esbuf) -{ - int remain = esbuf->size; - while(remain > 0) - { - remain -= write(esbuf->fd, esbuf->buffer+(esbuf->size-remain), remain); - } - return 0; -} - -#if 0 -未使用なため駆除 -/* - * packet dump - */ -void dump_packet( const uint8_t *packet ) -{ - int i = 0; - uint8_t *p = (uint8_t*)packet; - char tmp[17]; - - printf("HEADER 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F <ASCII>\n"); - while(i < LENGTH_PACKET) { - if ( (i%16) == 0 ) { - printf("0x%04X ", i); - } - printf("%02x ", *(p+i)); - if ( isprint(*(p+i)) ){ - tmp[i%16] = *(p+i); - } - else { - tmp[i%16] = '.'; - } - if ((i%16) == 15) { - tmp[sizeof(tmp)-1] = '\0'; - printf(" %s\n", tmp); - } - i++; - } - putchar('\n'); -} -#endif - -/* - * TOT の JST_time を解析する - */ -static int parse_tot( const unsigned char* packet, time_t *t ) -{ - /* 注意事項 - * 本当は TOT が有効かどうかをチェックするべきですがしていません - * サマータイム関係は無視しています - */ - struct tm tm; - time_t t2; - int k; - uint8_t *p = (uint8_t*)packet; - unsigned int MJD; - tm.tm_wday = 0; - tm.tm_yday = 0; - tm.tm_isdst = 0; - - p += 8; - MJD = (*(p) & 0xff) <<8; - p++; - MJD |= *(p) & 0xff; - - /* ARIB STD-B10 第2部 付録C の公式より MJD to YYYYMMDD */ - tm.tm_year = (int)floor((MJD - 15078.2)/365.25); - tm.tm_mon = (int)floor((MJD - 14956.1 - floor(tm.tm_year * 365.25))/30.6001); - tm.tm_mday = MJD - 14956 - floor(tm.tm_year * 365.25) - floor(tm.tm_mon * 30.6001); - if ( tm.tm_mon == 14 || tm.tm_mon == 15 ) - k = 1; - else - k = 0; - tm.tm_year += k; - tm.tm_mon = tm.tm_mon -1 - k * 12; - tm.tm_mon--; - - /* HHMISSは2進化10進数 */ - p++; - tm.tm_hour = ((*p & 0xf0) >>4)*10 + (*p & 0x0f); - p++; - tm.tm_min = ((*p & 0xf0) >>4)*10 + (*p & 0x0f); - p++; - tm.tm_sec = ((*p & 0xf0) >>4)*10 + (*p & 0x0f); - - *t = mktime(&tm); - time(&t2); - - return TRUE; -} - -static int64_t get_pts(const uint8_t *p) -{ - int64_t pts = (int64_t)((p[0] >> 1) & 0x07) << 30; - pts |= (AV_RB16(p + 1) >> 1) << 15; - pts |= AV_RB16(p + 3) >> 1; - return pts; -} - -static int get_pmt_version(const uint8_t *p) -{ - return ((p[6] >> 1) & 0x1f); -} - -#if 0 -未使用なため駆除 -void search_mpeg_system_header(const uint8_t *packet) -{ - int i; - uint8_t *p = (uint8_t*)packet; - i = 0; - for( i=0; i < LENGTH_PACKET-4; i++) { - if( p[i] == 0x00 && p[i+1] == 0x00 && p[i+2] == 0x01 && p[i+3] == 0xb8 ){ - dump_packet(packet ); - } - } -} -#endif - -/* - * この関数では、現在の仕様では、先頭位置の「次の」ADTS start codeまでの長さを返却する - * ret == 0 : 仕様上あり得ない(esbuf先頭はヘッダ先頭であるため) - * ret > 0 : 見つかった場合 - * ret == -1 : 見つからなかった場合 - */ -static int next_adts_start_code(splitesbuf_t *esbuf, int offset) -{ - /* - * start code prefix のうち、先頭12bit は 1 固定 - */ - uint16_t adts_start_code = 0xfff0; - int i = offset +1; - uint16_t startcode = 0; - - /* 小さすぎる */ - if(esbuf->size -offset < sizeof(adts_start_code)){ - return -1; - } - for(; i < esbuf->size - sizeof(adts_start_code); i++) { - startcode = AV_RB16(esbuf->buffer+i); - if( startcode == adts_start_code ) { /* 該当位置から12bit連続1が立っているか? */ - return (i-offset); - } - } - return -1; -} - -/* 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 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; /* データブロックまでの残量 */ - /* - * サンプリング周波数テーブル(ヘッダのsampling_frequency_indexが添字) - * 単位:Hz - */ - int sampling_frequency_table[16] = - { - 96000, - 88200, - 64000, - 48000, - 44100, - 32000, - 24000, - 22050, - 16000, - 12000, - 11025, - 8000, - -1, - -1, - -1, - -1 - }; - - uint8_t *p = esbuf->buffer; - if ( esbuf->size < 8 ) { - return -1; - } - - id = get_adif_id(p+1); - layer = get_adif_layer(p+1); - protection_absent = get_adif_protection_absent(p+1); - profile = get_adif_profile(p+2); - sampling_frequency_index = get_adif_sampling_frequency_index(p+2); - private_bit = get_adif_private_bit(p+2); - channel_configuration = get_adif_channel_configuration(p+3); - original_copy = get_adif_original_copy(p+3); - home = get_adif_home(p+3); - copyright_identification_bit = get_adif_copyright_idication_bit(p+3); - copyright_identification_start = get_adif_copyright_idication_start(p+3); - aac_frame_length = get_adif_aac_frame_length(p+3); - adts_buffer_fullness = get_adts_buffer_fullness(p+5); - no_raw_data_blocks_in_frame = get_adts_no_raw_data_blocks_in_frame(p+5); - - /* - * とりあえず return は サンプリング周波数としておく - * 本当は取得した情報を構造体にして返却する方がいいのだろうけど、 - * 利用する予定もないので取得するだけにしておく - */ - return sampling_frequency_table[sampling_frequency_index]; -} - -static int get_adif_id(uint8_t *p) -{ - return ((*p & 0x08) >>3); -} - -static int get_adif_layer(uint8_t *p) -{ - return ((*p & 0x06) >>1); -} - -static int get_adif_protection_absent(uint8_t *p) -{ - return (*p & 0x01); -} - -static int get_adif_profile(uint8_t *p) -{ - return ((*p & 0xc0) >>6); -} - -static int get_adif_sampling_frequency_index(uint8_t *p) -{ - return ((*p & 0x3c) >>2); -} - -static int get_adif_private_bit(uint8_t *p) -{ - return ((*p & 0x02) >>1); -} - -static int get_adif_channel_configuration(uint8_t *p) -{ - return ((*p & 0x01) <<2 | (*(p+1) & 0xc0 >>6) ); -} - -static int get_adif_original_copy(uint8_t *p) -{ - return (*p & 0x20 >>5 ); -} - -static int get_adif_home(uint8_t *p) -{ - return (*p & 0x10 >>4 ); -} - -static int get_adif_copyright_idication_bit(uint8_t *p) -{ - return (*p & 0x08 >>3 ); -} - -static int get_adif_copyright_idication_start(uint8_t *p) -{ - return (*p & 0x04 >>2 ); -} - -static int get_adif_aac_frame_length(uint8_t *p) -{ - return ( ((*p & 0x02) <<11) || ((*(p+1) & 0xff) <<3) || ((*(p+2) & 0xe0) >>5) ); -} - -static int get_adts_buffer_fullness(uint8_t *p) -{ - return ( ((*p & 0x1f) <<6) || ((*(p+1) &0xfc) >>2)); -} - -static int get_adts_no_raw_data_blocks_in_frame(uint8_t *p) -{ - return (*p & 0x03); -} - -#define GOP_START_CODE (0x000001b8) -/* GOP START CODE を検索する */ -static int search_gop_start_code(splitesbuf_t *esbuf) -{ - uint32_t gop_start_code = GOP_START_CODE; - int i; - - /* 小さすぎる */ - if ( esbuf->size < sizeof gop_start_code ){ - return -1; - } - for(i = 0; i < esbuf->size - sizeof gop_start_code; i++) { - if ( (AV_RB32(esbuf->buffer +i)) == gop_start_code ) { - return i; - } - } - return -1; -} - -/* ES 出力するファイルを作成する */ -static int creat_es_file(splitter *sp, int sid, int pid, int av_flag) -{ - /* - * 出力ESファイルの命名規則は以下とする - * - * ファイル名のベースは --es オプションの引数 - * 以下の形式で命名して、ファイルオープンまで実施する。 - * ファイル名prefix_SID_AVのプログラム内番号.m2v - * ファイル名prefix_SID_AVのプログラム内番号.aac - * - * !!注意!! - * MPEG-2/MPEG-4 AAC 以外のオーディオが来た場合の処理が未実装 - */ - - char filename[PATH_MAX]; - int size = 0; - char *suffix = NULL; - int av_nb = 0; - char suffix_a[] = "aac"; - char suffix_v[] = "m2v"; - filename[0] = '\0'; - - /* ちょっとこの辺のコードイケてないので後から直すかも */ - if ( av_flag == TSS_STREAM_TYPE_VIDEO ) { - suffix = suffix_v; - av_nb = sp->program[sid].video_nb -1; - } else if ( av_flag == TSS_STREAM_TYPE_AUDIO ){ - suffix = suffix_a; - av_nb = sp->program[sid].audio_nb -1; - } else { - /* ここはありえない */ - return -1; - } - size = strlen(sp->filename); - - if ( size +16 < sizeof(filename) ) { - snprintf(filename, sizeof(filename), "%s_%05d_%02d.%s", sp->filename, sid, av_nb, suffix); - filename[PATH_MAX-1] = '\0'; - } else { - /* ファイル名つけられなくて困るでござるの巻 */ - return -1; - } - umask(0133); - if ( !(sp->esbuf[pid]->fd = open(filename, O_CREAT|O_APPEND|O_RDWR, 00644)) ) { - 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/src/tssplitter_lite.h Mon May 05 21:59:36 2014 +0900 +++ b/src/tssplitter_lite.h Mon May 05 22:08:21 2014 +0900 @@ -23,7 +23,6 @@ #define __STDC_FORMAT_MACROS #include <inttypes.h> #include <unistd.h> -#include <limits.h> #define LENGTH_PACKET (188) #define MAX_PID (8192) @@ -37,181 +36,42 @@ #define TSS_NULL (-2) #define LENGTH_PAT_HEADER (12) #define C_CHAR_COMMA ',' -#define C_CHAR_DOT '.' -#define LENGTH_TS_HEADER (4) -#define LENGTH_PES_HEADER (9) -#define LENGTH_PTS (5) - -/* 改訂版デジタル放送教科書(上) P101 表1 ARIBでのPSI/SIの種類より参照 */ -#define PAT (0x0000) -//#define PMT /* PATによる間接指定 */ -#define CAT (0x0001) -#define NIT (0x0010) -#define SDT (0x0011) -#define BAT (0x0011) -#define EIT (0x0012) /* 0x0026, 0x0027 */ -#define RST (0x0013) -#define TDT (0x0014) /* 地デジでは使用されない */ -#define TOT (0x0014) -#define LIT (0x0020) /* またはPMTによる間接指定 */ -#define ERT (0x0021) /* またはPMTによる間接指定 */ -//#define ITT /* PMTによる間接指定 */ -#define PCAT (0x0022) -#define BIT (0x0024) -#define NBIT (0x0025) -//#define ECM /* PMTによる間接指定 */ -//#define EMM /* CATによる間接指定 */ -#define LDT (0x0025) -#define DCT (0x0017) -//#define DTL /* DCTによる間接指定 */ -#define DIT (0x001e) -#define SIT (0x001f) -#define SDTT (0x0023) -#define CDT (0x0029) -//#define DSM-CC_Section /* PMTによる間接指定 */ - -/* セクションヘッダ長 */ -/* TS パケットに各セクションを設置する際、該当TSパケットの残サイズが - * いくつ以上あれば書き込めるかの判定に使用する。 - * デコードにはあまり重要では無いかも - */ -#define SECTION_LENGTH_PAT (8) -#define SECTION_LENGTH_PMT (8) -#define SECTION_LENGTH_CAT (8) -#define SECTION_LENGTH_NIT (8) -#define SECTION_LENGTH_BIT (8) -#define SECTION_LENGTH_SDT (11) -#define SECTION_LENGTH_EIT (14) /* H-EIT, M-EIT, L-EIT を示す */ -#define SECTION_LENGTH_SDTT (15) -#define SECTION_LENGTH_CDT (13) -#define SECTION_LENGTH_TOT (10) - -enum { - PTS_FLAG = 0x80, - DTS_FLAG = 0x40, - ESCR_FLAG = 0x20, - ES_RATE_FLAG = 0x10, - DSM_TRICK_MODE_FLAG = 0x08, - COPY_INFO_FLAG = 0x04, - CRC_FLAG = 0x02, - EXTENSION_FLAG = 0x01 -}; +#define SECTION_CONTINUE (1) -enum { - PES_PRIVATE_DATA_FLAG = 0x80, - PACK_HEADER_FIELD_FLAG = 0x40, - PROGRAM_PACKET_SEQUENCE_COUNTER = 0x20, - PSTD_BUFFER_FLAG = 0x10, - PES_EXTENSION_FLAG2 = 0x01 -}; - -/* - * PCRからSTCを生成する処理方式 - * 1. PCRを二つ取得するまでループ(1.から4.までは初期処理で実施すること) - * 2. ループ開始時刻(PCR)と、ループ抜けた時刻(PCR)の差分を取る - * 3. ループ開始〜終了の間に処理したパケット数を数える - * 4. (2.のPCRの進んだ時間/3.のパケット数) の計算によって、1パケットによって進むPCRを想定する - * 5. TS受信時に、1つのパケットを処理する度に4.の想定する経過時刻をPCRに足し込んでSTCとする - * 6. PCRを新規に取得したら、STCを補正(そのまま代入)する - */ -#define MAX_VIDEO (16) -#define MAX_AUDIO (32) -typedef struct _program_t -{ - int64_t stc; - 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 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 */ - int video_nb; /* PMT に存在するビデオストリームの数 */ - int audio_nb; /* PMT に存在する音声ストリームの数 */ - int video[MAX_VIDEO]; /* PS出力する場合に使うかも */ - int audio[MAX_AUDIO]; /* PS出力する場合に使うかも */ -} program_t; -/* - * program_t をサービスID分準備して、使用するイメージでいたけど、 - * サービスIDの最大値は0xFFFFであるので、静的に確保すると stack が簡単に溢るので、 - * 実行時に malloc とするかなぁ - * 本当は必要なだけallocするのが好ましいのだけど… - */ - -typedef struct _splitpesbuf_t -{ - program_t *Program; - int64_t pts; - int64_t dts; - int size; - u_char buffer[3*1024*1024]; -} splitpesbuf_t; - -typedef struct _splitesbuf_t -{ - program_t *Program; - int64_t pts; - int64_t dts; - int started; /* 該当ESが蓄積開始しているか */ - int random_access_indicator; /* TS の random_access_indicator */ - int fd; /* 該当ESのfd */ - int size; - 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; - +typedef struct pmt_version { + int pid; + int version; + int packet; +} pmt_version; /** * 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; int pmt_retain; int pmt_counter; int avail_pmts[MAX_SERVICES]; + pmt_version pmt_version[MAX_SERVICES]; int num_pmts; - splitpesbuf_t *pesbuf[MAX_PID]; - splitesbuf_t *esbuf[MAX_PID]; - program_t *program; - int pid_sid_table[MAX_PID]; /* pid to sid の変換を行うためのテーブル */ - time_t time_cue; - time_t time_tot; - int tot_packet_nb; /* TOT受信時のパケット受信数 */ + uint16_t section_remain[MAX_PID]; // セクション残りバイト数 + uint8_t packet_seq[MAX_PID]; // 巡回カウンタ + int split_select_finish; time_t split_start_time; - int split_select_finish; } splitter; -/* b25 decoder would hoard up large chank */ typedef struct _splitbuf_t { - int size; - int buffer_length; - u_char *buffer; + u_char* buffer; + int buffer_size; + int buffer_filled; } splitbuf_t; -splitter* split_startup(char *sid, char *filename, char *cue_time); +splitter* split_startup(char *sid); 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);