├── readme.txt ├── README ├── src ├── Makefile └── tsselect.c └── .github └── workflows └── build-test.yml /readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xtne6f/tsselect_gcc/HEAD/readme.txt -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | tsselect linux 2 | 3 | 1.目標 4 | marumo氏のtsselectのLinuxへのポート。車輪の何度目かの再開発 5 | 6 | 2.変更点 7 | 以下の機能を追加 8 | - 入力または出力に "-" を指定すると標準入出力とみなす 9 | - 同期エラーだけでなく連続性指標によるドロップ検出部分も "resync[n](drop only) :" として報告 10 | - 9個以上の同期エラーもすべて詳細表示 11 | - 同期エラー報告時、前後のTDT/TOT時刻が得られていれば "time : 前時刻, 後時刻" として表示 12 | (ファイル先頭などで前後どちらかの時刻が不明のときは "--" になる) 13 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CC = gcc 3 | CFLAGS = -O2 -D_XOPEN_SOURCE=600 -D_FILE_OFFSET_BITS=64 4 | LDFLAGS = 5 | OBJS = tsselect.o 6 | PROGRAM = tsselect 7 | DEST = /usr/local/bin 8 | 9 | $(PROGRAM): $(OBJS) 10 | $(CC) $(LDFLAGS) -o $@ $(OBJS) 11 | 12 | .c.o: 13 | $(CC) $(CFLAGS) -c $< 14 | 15 | all:$(PROGRAM) 16 | 17 | clean: 18 | rm $(OBJS) $(PROGRAM) 19 | 20 | install:$(PROGRAM) 21 | install -s $(PROGRAM) $(DEST) 22 | 23 | -------------------------------------------------------------------------------- /.github/workflows/build-test.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | permissions: 3 | contents: read 4 | jobs: 5 | build-test: 6 | runs-on: ${{ matrix.os }} 7 | strategy: 8 | matrix: 9 | os: 10 | - ubuntu-latest 11 | - macos-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Build 15 | working-directory: ./src 16 | run: make 17 | - name: Test 18 | working-directory: ./src 19 | run: | 20 | printf "" >src.m2t 21 | for i in `seq 0 9`; do 22 | printf "\x47\0\0\x1$i" >>src.m2t 23 | for j in `seq 23`; do printf UUUUUUUU >>src.m2t; done 24 | printf "\x47\x12\x34\x1$i" >>src.m2t 25 | for j in `seq 23`; do printf UUUUUUUU >>src.m2t; done 26 | printf "\x47\x12\x35\x1$i" >>src.m2t 27 | for j in `seq 23`; do printf UUUUUUUU >>src.m2t; done 28 | done 29 | test "2911918438 3760" = "`./tsselect src.m2t - -x 0x1234 | cksum | head -c 15`" 30 | -------------------------------------------------------------------------------- /src/tsselect.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #ifdef _WIN32 7 | #include 8 | #include 9 | #define my_fseek _fseeki64 10 | #define my_ftell _ftelli64 11 | 12 | #ifdef UNICODE 13 | #include 14 | #define my_fopen _wfopen 15 | #define FOPEN_BINARY(mode) L ## mode L"bS" 16 | #define PRI_PATH_STR "ls" 17 | typedef const wchar_t * PATH_STR; 18 | #else 19 | #define my_fopen fopen 20 | #define FOPEN_BINARY(mode) mode "bS" 21 | #define PRI_PATH_STR "s" 22 | typedef const char * PATH_STR; 23 | #endif 24 | 25 | #else 26 | #define my_fseek fseeko 27 | #define my_ftell ftello 28 | #define my_fopen fopen 29 | #define FOPEN_BINARY(mode) mode 30 | #define PRI_PATH_STR "s" 31 | typedef const char * PATH_STR; 32 | #endif 33 | 34 | /* report drops as with resync */ 35 | #ifndef REPORT_DROP 36 | #define REPORT_DROP 1 37 | #endif 38 | 39 | typedef struct { 40 | 41 | int pid; 42 | int last_continuity_counter; 43 | 44 | int64_t first; 45 | int64_t total; 46 | int64_t error; 47 | int64_t drop; 48 | int64_t scrambling; 49 | 50 | unsigned char last_packet[188]; 51 | int duplicate_count; 52 | int report_drop; 53 | 54 | } TS_STATUS; 55 | 56 | typedef struct { 57 | 58 | int64_t miss; 59 | int64_t sync; 60 | 61 | int64_t drop_count; 62 | 63 | short drop_pid[4]; 64 | int64_t drop_pos[4]; 65 | 66 | int last_mjd, mjd; 67 | int last_h, h; 68 | int last_m, m; 69 | int last_s, s; 70 | 71 | } RESYNC_REPORT; 72 | 73 | typedef struct { 74 | int sync; 75 | int transport_error_indicator; 76 | int payload_unit_start_indicator; 77 | int transport_priority; 78 | int pid; 79 | int transport_scrambling_control; 80 | int adaptation_field_control; 81 | int continuity_counter; 82 | } TS_HEADER; 83 | 84 | typedef struct { 85 | 86 | int adaptation_field_length; 87 | 88 | int discontinuity_counter; 89 | int random_access_indicator; 90 | int elementary_stream_priority_indicator; 91 | int pcr_flag; 92 | int opcr_flag; 93 | int splicing_point_flag; 94 | int transport_private_data_flag; 95 | int adaptation_field_extension_flag; 96 | 97 | int64_t program_clock_reference; 98 | int64_t original_program_clock_reference; 99 | 100 | int splice_countdown; 101 | 102 | int transport_private_data_length; 103 | 104 | int adaptation_field_extension_length; 105 | int ltw_flag; 106 | int piecewise_rate_flag; 107 | int seamless_splice_flag; 108 | int ltw_valid_flag; 109 | int ltw_offset; 110 | int piecewise_rate; 111 | int splice_type; 112 | int64_t dts_next_au; 113 | 114 | } ADAPTATION_FIELD; 115 | 116 | static void show_usage(); 117 | 118 | static void tsdump(PATH_STR path); 119 | static void tsselect(PATH_STR src, PATH_STR dst, const unsigned char *pid); 120 | static int select_unit_size(unsigned char *head, unsigned char *tail); 121 | static unsigned char *resync(unsigned char *head, unsigned char *tail, int unit_size); 122 | static unsigned char *resync_force(unsigned char *head, unsigned char *tail, int unit_size); 123 | static void extract_ts_header(TS_HEADER *dst, unsigned char *packet); 124 | static void extract_adaptation_field(ADAPTATION_FIELD *dst, unsigned char *data); 125 | static int check_unit_invert(unsigned char *head, unsigned char *tail); 126 | 127 | static void add_drop_info(RESYNC_REPORT *report, int count, int pid, int64_t pos); 128 | static void print_resync_report(RESYNC_REPORT *report, int count); 129 | static void set_resync_report_last_time(RESYNC_REPORT *report, int mjd, int h, int m, int s); 130 | static void update_resync_report_time(RESYNC_REPORT *report, int count, int mjd, int h, int m, int s); 131 | static void mjd_to_ymd(int mjd, int *y, int *m, int *d); 132 | 133 | static int find_packet_time_data(unsigned char **time_data, const TS_HEADER *hdr, unsigned char *packet); 134 | static void show_tdt_or_tot(TS_HEADER *hdr, unsigned char *packet, int64_t pos); 135 | 136 | #if defined(_WIN32) && defined(UNICODE) 137 | int wmain(int argc, wchar_t **argv) 138 | #else 139 | int main(int argc, char **argv) 140 | #endif 141 | { 142 | if(argc < 2){ 143 | show_usage(); 144 | exit(EXIT_FAILURE); 145 | } 146 | 147 | if(argc == 2){ 148 | tsdump(argv[1]); 149 | }else{ 150 | int i,n; 151 | int exclude; 152 | unsigned char pid[8192]; 153 | 154 | memset(pid, 0, sizeof(pid)); 155 | exclude = 0; 156 | for(i=3;i= 0) && (n < 8192) ){ 176 | pid[n] = 1; 177 | } 178 | } 179 | 180 | if(exclude){ 181 | for(i=0;i<8192;i++){ 182 | pid[i] = !pid[i]; 183 | } 184 | } 185 | 186 | tsselect(argv[1], argv[2], pid); 187 | 188 | } 189 | 190 | return EXIT_SUCCESS; 191 | } 192 | 193 | static void show_usage() 194 | { 195 | fprintf(stderr, "tsselect - MPEG-2 TS stream(pid) selector ver. 0.1.8\n"); 196 | fprintf(stderr, "usage: tsselect src.m2t|- [dst.m2t|- pid [more pid ..]]\n"); 197 | fprintf(stderr, "\n"); 198 | fprintf(stderr, "ex: dump \"src.m2t\" TS information\n"); 199 | fprintf(stderr, " tsselect src.m2t\n"); 200 | fprintf(stderr, "\n"); 201 | fprintf(stderr, "ex: remux \"src.m2t\" to \"dst.m2t\" which contains pid=0x1000 and pid=0x1001\n"); 202 | fprintf(stderr, " tsselect src.m2t dst.m2t 0x1000 0x1001\n"); 203 | fprintf(stderr, "\n"); 204 | fprintf(stderr, "ex: remux \"src.m2t\" to \"dst.m2t\" exclude pid=0x0012(EIT) pid=0x0014(TOT)\n"); 205 | fprintf(stderr, " tsselect src.m2t dst.m2t -x 0x0012 0x0014\n"); 206 | fprintf(stderr, "\n"); 207 | } 208 | 209 | static void tsdump(PATH_STR path) 210 | { 211 | FILE *fp; 212 | 213 | int pid; 214 | int idx; 215 | int lcc; 216 | int i,m,n; 217 | int unit_size; 218 | int dropped; 219 | 220 | int64_t offset; 221 | int64_t total; 222 | 223 | TS_STATUS *stat; 224 | TS_HEADER header; 225 | ADAPTATION_FIELD adapt; 226 | int last_mjd = 0; 227 | int last_h = 0; 228 | int last_m = 0; 229 | int last_s = 0; 230 | 231 | RESYNC_REPORT *resync_report, *rr; 232 | int resync_count; 233 | 234 | unsigned char *p; 235 | unsigned char *curr; 236 | unsigned char *tail; 237 | 238 | unsigned char buf[32768]; 239 | 240 | fp = NULL; 241 | stat = NULL; 242 | 243 | resync_report = (RESYNC_REPORT *)calloc(1, sizeof(RESYNC_REPORT)); 244 | resync_count = 0; 245 | 246 | if(path[0] == '-' && !path[1]){ 247 | fp = stdin; 248 | #ifdef _WIN32 249 | if(_setmode(_fileno(fp), _O_BINARY) < 0){ 250 | fp = NULL; 251 | } 252 | #endif 253 | }else{ 254 | fp = my_fopen(path, FOPEN_BINARY("r")); 255 | } 256 | if(fp == NULL){ 257 | fprintf(stderr, "error - failed on open(%" PRI_PATH_STR ") [src]\n", path); 258 | goto LAST; 259 | } 260 | 261 | if(fp == stdin){ 262 | total = 0; 263 | }else{ 264 | my_fseek(fp, 0, SEEK_END); 265 | total = my_ftell(fp); 266 | my_fseek(fp, 0, SEEK_SET); 267 | } 268 | 269 | stat = (TS_STATUS *)calloc(8192, sizeof(TS_STATUS)); 270 | if(stat == NULL){ 271 | fprintf(stderr, "error - failed on malloc(size=%d)\n", (int)(sizeof(TS_STATUS)*8192)); 272 | goto LAST; 273 | } 274 | 275 | for(i=0;i<8192;i++){ 276 | stat[i].pid = i; 277 | stat[i].last_continuity_counter = -1; 278 | stat[i].first = -1; 279 | stat[i].report_drop = REPORT_DROP; 280 | } 281 | 282 | offset = 0; 283 | idx = 0; 284 | n = fread(buf, 1, sizeof(buf) / 4, fp); 285 | 286 | unit_size = select_unit_size(buf, buf+n); 287 | if(unit_size < 188){ 288 | fprintf(stderr, "error - failed on select_unit_size()\n"); 289 | goto LAST; 290 | } 291 | 292 | do { 293 | curr = buf; 294 | tail = buf + n; 295 | while( (curr+unit_size) < tail ){ 296 | if( (curr[0] != 0x47) || (curr[unit_size] != 0x47) ){ 297 | if(resync_report){ 298 | rr = resync_report; 299 | resync_report = (RESYNC_REPORT *)calloc(resync_count+1, sizeof(RESYNC_REPORT)); 300 | if(resync_report){ 301 | memcpy(resync_report, rr, sizeof(RESYNC_REPORT)*resync_count); 302 | resync_report[resync_count].miss = offset+(curr-buf); 303 | } 304 | free(rr); 305 | } 306 | p = resync(curr, tail, unit_size); 307 | if(p == NULL){ 308 | break; 309 | } 310 | curr = p; 311 | if(resync_report){ 312 | resync_report[resync_count].sync = offset+(curr-buf); 313 | set_resync_report_last_time(resync_report + resync_count, last_mjd, last_h, last_m, last_s); 314 | } 315 | resync_count += 1; 316 | for(i=0;i<8192;i++){ 317 | stat[i].report_drop = 0; 318 | } 319 | if( (curr+unit_size) > tail ){ 320 | break; 321 | } 322 | } 323 | 324 | extract_ts_header(&header, curr); 325 | if(header.adaptation_field_control & 2){ 326 | extract_adaptation_field(&adapt, curr+4); 327 | }else{ 328 | memset(&adapt, 0, sizeof(adapt)); 329 | } 330 | 331 | pid = header.pid; 332 | if(pid == 0x14){ 333 | /* maybe TDT or TOT */ 334 | unsigned char *time_data; 335 | int table_id = find_packet_time_data(&time_data, &header, curr); 336 | if(table_id == 0x70 || table_id == 0x73){ 337 | /* TDT or TOT */ 338 | last_mjd = (time_data[0] << 8) | time_data[1]; 339 | last_mjd = last_mjd < 15079 ? 15079 : last_mjd; 340 | last_h = ((time_data[2] >> 4) & 3) * 10 + (time_data[2] & 15); 341 | last_m = ((time_data[3] >> 4) & 7) * 10 + (time_data[3] & 15); 342 | last_s = ((time_data[4] >> 4) & 7) * 10 + (time_data[4] & 15); 343 | update_resync_report_time(resync_report, resync_count, last_mjd, last_h, last_m, last_s); 344 | } 345 | } 346 | if(stat[pid].first < 0){ 347 | stat[pid].first = offset + (curr-buf); 348 | } 349 | lcc = stat[pid].last_continuity_counter; 350 | if( (lcc >= 0) && (adapt.discontinuity_counter == 0) ){ 351 | dropped = 0; 352 | if( pid == 0x1fff ){ 353 | // null packet - drop count has no mean 354 | // do nothing 355 | }else if( (header.adaptation_field_control & 0x01) == 0 ){ 356 | // no payload : continuity_counter should not increment 357 | if(lcc != header.continuity_counter){ 358 | dropped = 1; 359 | } 360 | }else if(lcc == header.continuity_counter){ 361 | // has payload and same continuity_counter 362 | if(memcmp(stat[pid].last_packet, curr, 188) != 0){ 363 | // non-duplicate packet 364 | dropped = 1; 365 | } 366 | stat[pid].duplicate_count += 1; 367 | if(stat[pid].duplicate_count > 1){ 368 | // duplicate packet count exceeds limit (two) 369 | dropped = 1; 370 | } 371 | }else{ 372 | m = (lcc + 1) & 0x0f; 373 | if(m != header.continuity_counter){ 374 | dropped = 1; 375 | } 376 | stat[pid].duplicate_count = 0; 377 | } 378 | if(dropped){ 379 | if(stat[pid].report_drop){ 380 | if(resync_report){ 381 | rr = resync_report; 382 | resync_report = (RESYNC_REPORT *)calloc(resync_count+1, sizeof(RESYNC_REPORT)); 383 | if(resync_report){ 384 | memcpy(resync_report, rr, sizeof(RESYNC_REPORT)*resync_count); 385 | resync_report[resync_count].miss = 386 | resync_report[resync_count].sync = offset+(curr-buf); 387 | set_resync_report_last_time(resync_report + resync_count, last_mjd, last_h, last_m, last_s); 388 | } 389 | free(rr); 390 | } 391 | resync_count += 1; 392 | for(i=0;i<8192;i++){ 393 | stat[i].report_drop = 0; 394 | } 395 | } 396 | stat[pid].drop += 1; 397 | add_drop_info(resync_report, resync_count, pid, offset+(curr-buf)); 398 | } 399 | } 400 | stat[pid].report_drop = REPORT_DROP; 401 | stat[pid].last_continuity_counter = header.continuity_counter; 402 | stat[pid].total += 1; 403 | if(header.transport_error_indicator != 0){ 404 | stat[pid].error += 1; 405 | } 406 | memcpy(stat[pid].last_packet, curr, 188); 407 | if(header.transport_scrambling_control){ 408 | stat[pid].scrambling += 1; 409 | } 410 | curr += unit_size; 411 | } 412 | 413 | offset += (curr-buf); 414 | 415 | if( (idx & 0x1f) == 0 ){ 416 | if(total <= 0){ 417 | fprintf(stderr, "\rprocessing: %5dM", (int)(offset/1024/1024)); 418 | }else{ 419 | n = (int)(10000*offset/total); 420 | fprintf(stderr, "\rprocessing: %2d.%02d%%", n/100, n%100); 421 | } 422 | } 423 | idx += 1; 424 | 425 | n = tail - curr; 426 | if(n > 0){ 427 | memcpy(buf, curr, n); 428 | } 429 | m = fread(buf+n, 1, sizeof(buf)-n, fp); 430 | if(m < 1){ 431 | break; 432 | } 433 | n += m; 434 | 435 | } while(n > unit_size); 436 | 437 | curr = buf; 438 | tail = buf + n; 439 | while( (curr+188) <= tail ){ 440 | if(curr[0] != 0x47){ 441 | if(resync_report){ 442 | rr = resync_report; 443 | resync_report = (RESYNC_REPORT *)calloc(resync_count+1, sizeof(RESYNC_REPORT)); 444 | if(resync_report){ 445 | memcpy(resync_report, rr, sizeof(RESYNC_REPORT)*resync_count); 446 | resync_report[resync_count].miss = offset+(curr-buf); 447 | } 448 | free(rr); 449 | } 450 | p = resync_force(curr, tail, unit_size); 451 | if(p == NULL){ 452 | break; 453 | } 454 | curr = p; 455 | if(resync_report){ 456 | resync_report[resync_count].sync = offset+(curr-buf); 457 | set_resync_report_last_time(resync_report + resync_count, last_mjd, last_h, last_m, last_s); 458 | } 459 | resync_count += 1; 460 | for(i=0;i<8192;i++){ 461 | stat[i].report_drop = 0; 462 | } 463 | if( (p+188) > tail ){ 464 | break; 465 | } 466 | } 467 | extract_ts_header(&header, curr); 468 | if(header.adaptation_field_control & 2){ 469 | extract_adaptation_field(&adapt, curr+4); 470 | }else{ 471 | memset(&adapt, 0, sizeof(adapt)); 472 | } 473 | pid = header.pid; 474 | if(stat[pid].first < 0){ 475 | stat[pid].first = offset + (curr-buf); 476 | } 477 | lcc = stat[pid].last_continuity_counter; 478 | if( (lcc >= 0) && (adapt.discontinuity_counter == 0) ){ 479 | dropped = 0; 480 | if( pid == 0x1fff ){ 481 | // null packet - drop count has no mean 482 | // do nothing 483 | }else if( (header.adaptation_field_control & 0x01) == 0 ){ 484 | // no payload : continuity_counter should not increment 485 | if(lcc != header.continuity_counter){ 486 | dropped = 1; 487 | } 488 | }else if(lcc == header.continuity_counter){ 489 | // has payload and same continuity_counter 490 | if(memcmp(stat[pid].last_packet, curr, 188) != 0){ 491 | // non-duplicate packet 492 | dropped = 1; 493 | } 494 | stat[pid].duplicate_count += 1; 495 | if(stat[pid].duplicate_count > 1){ 496 | // duplicate packet count exceeds limit (two) 497 | dropped = 1; 498 | } 499 | }else{ 500 | m = (lcc + 1) & 0x0f; 501 | if(m != header.continuity_counter){ 502 | dropped = 1; 503 | } 504 | stat[pid].duplicate_count = 0; 505 | } 506 | if(dropped){ 507 | if(stat[pid].report_drop){ 508 | if(resync_report){ 509 | rr = resync_report; 510 | resync_report = (RESYNC_REPORT *)calloc(resync_count+1, sizeof(RESYNC_REPORT)); 511 | if(resync_report){ 512 | memcpy(resync_report, rr, sizeof(RESYNC_REPORT)*resync_count); 513 | resync_report[resync_count].miss = 514 | resync_report[resync_count].sync = offset+(curr-buf); 515 | set_resync_report_last_time(resync_report + resync_count, last_mjd, last_h, last_m, last_s); 516 | } 517 | free(rr); 518 | } 519 | resync_count += 1; 520 | for(i=0;i<8192;i++){ 521 | stat[i].report_drop = 0; 522 | } 523 | } 524 | stat[pid].drop += 1; 525 | add_drop_info(resync_report, resync_count, pid, offset+(curr-buf)); 526 | } 527 | } 528 | stat[pid].report_drop = REPORT_DROP; 529 | stat[pid].last_continuity_counter = header.continuity_counter; 530 | stat[pid].total += 1; 531 | if(header.transport_error_indicator != 0){ 532 | stat[pid].error += 1; 533 | } 534 | memcpy(stat[pid].last_packet, curr, 188); 535 | if(header.transport_scrambling_control){ 536 | stat[pid].scrambling += 1; 537 | } 538 | curr += unit_size; 539 | } 540 | 541 | fprintf(stderr, "\rprocessing: finish\n"); 542 | fflush(stderr); 543 | 544 | LAST: 545 | if(resync_count > 0){ 546 | print_resync_report(resync_report, resync_count); 547 | } 548 | free(resync_report); 549 | 550 | if(stat){ 551 | for(i=0;i<8192;i++){ 552 | if(stat[i].total > 0){ 553 | printf("pid=0x%04x, total=%8"PRId64", d=%3"PRId64", e=%3"PRId64", scrambling=%"PRId64", offset=%"PRId64"\n", i, stat[i].total, stat[i].drop, stat[i].error, stat[i].scrambling, stat[i].first); 554 | } 555 | } 556 | free(stat); 557 | stat = NULL; 558 | } 559 | 560 | if(fp != NULL){ 561 | if(fp != stdin){ 562 | fclose(fp); 563 | } 564 | fp = NULL; 565 | } 566 | } 567 | 568 | static void tsselect(PATH_STR src, PATH_STR dst, const unsigned char *pid) 569 | { 570 | FILE *sfp, *dfp; 571 | 572 | int m,n; 573 | int idx; 574 | int unit_size; 575 | 576 | TS_HEADER header; 577 | 578 | int64_t offset; 579 | int64_t total; 580 | 581 | unsigned char *p; 582 | unsigned char *curr; 583 | unsigned char *tail; 584 | 585 | unsigned char buf[8192]; 586 | 587 | sfp = NULL; 588 | dfp = NULL; 589 | 590 | if(src[0] == '-' && !src[1]){ 591 | sfp = stdin; 592 | #ifdef _WIN32 593 | if(_setmode(_fileno(sfp), _O_BINARY) < 0){ 594 | sfp = NULL; 595 | } 596 | #endif 597 | }else{ 598 | sfp = my_fopen(src, FOPEN_BINARY("r")); 599 | } 600 | if(sfp == NULL){ 601 | fprintf(stderr, "error - failed on open(%" PRI_PATH_STR ") [src]\n", src); 602 | goto LAST; 603 | } 604 | 605 | if(dst[0] == '-' && !dst[1]){ 606 | dfp = stdout; 607 | #ifdef _WIN32 608 | if(_setmode(_fileno(dfp), _O_BINARY) < 0){ 609 | dfp = NULL; 610 | } 611 | #endif 612 | }else{ 613 | dfp = my_fopen(dst, FOPEN_BINARY("w")); 614 | } 615 | if(dfp == NULL){ 616 | fprintf(stderr, "error - failed on open(%" PRI_PATH_STR ") [dst]\n", dst); 617 | goto LAST; 618 | } 619 | 620 | if(sfp == stdin){ 621 | total = 0; 622 | }else{ 623 | my_fseek(sfp, 0, SEEK_END); 624 | total = my_ftell(sfp); 625 | my_fseek(sfp, 0, SEEK_SET); 626 | } 627 | 628 | offset = 0; 629 | idx = 0; 630 | n = fread(buf, 1, sizeof(buf), sfp); 631 | 632 | unit_size = select_unit_size(buf, buf+n); 633 | if(unit_size < 188){ 634 | fprintf(stderr, "error - failed on select_unit_size()\n"); 635 | goto LAST; 636 | } 637 | 638 | do { 639 | curr = buf; 640 | tail = buf + n; 641 | while( (curr+unit_size) < tail ){ 642 | if( (curr[0] != 0x47) || (curr[unit_size] != 0x47) ){ 643 | p = resync(curr, tail, unit_size); 644 | if(p == NULL){ 645 | break; 646 | } 647 | curr = p; 648 | if( (curr+unit_size) > tail ){ 649 | break; 650 | } 651 | } 652 | extract_ts_header(&header, curr); 653 | if(pid[header.pid] != 0){ 654 | m = fwrite(curr, 1, 188, dfp); 655 | if(m != 188){ 656 | fprintf(stderr, "error - failed on write() [dst]\n"); 657 | goto LAST; 658 | } 659 | } 660 | curr += unit_size; 661 | } 662 | 663 | offset += (curr-buf); 664 | 665 | if( (idx & 0x7f) == 0 ){ 666 | if(total <= 0){ 667 | fprintf(stderr, "\rprocessing: %5dM", (int)(offset/1024/1024)); 668 | }else{ 669 | n = (int)(10000*offset/total); 670 | fprintf(stderr, "\rprocessing: %2d.%02d%%", n/100, n%100); 671 | } 672 | } 673 | idx += 1; 674 | 675 | n = tail - curr; 676 | if(n > 0){ 677 | memcpy(buf, curr, n); 678 | } 679 | m = fread(buf+n, 1, sizeof(buf)-n, sfp); 680 | if(m < 1){ 681 | break; 682 | } 683 | n += m; 684 | }while(n > unit_size); 685 | 686 | curr = buf; 687 | tail = buf + n; 688 | while( (curr+188) <= tail ){ 689 | if(curr[0] != 0x47){ 690 | p = resync_force(curr, tail, unit_size); 691 | if(p == NULL){ 692 | break; 693 | } 694 | curr = p; 695 | if( (p+188) > tail ){ 696 | break; 697 | } 698 | } 699 | extract_ts_header(&header, curr); 700 | if(pid[header.pid] != 0){ 701 | m = fwrite(curr, 1, 188, dfp); 702 | if(m != 188){ 703 | fprintf(stderr, "error - failed on write() [dst]\n"); 704 | goto LAST; 705 | } 706 | } 707 | curr += unit_size; 708 | } 709 | 710 | fprintf(stderr, "\rprocessing: finish\n"); 711 | 712 | LAST: 713 | if(dfp != NULL){ 714 | if(dfp == stdout){ 715 | fflush(dfp); 716 | }else{ 717 | fclose(dfp); 718 | } 719 | dfp = NULL; 720 | } 721 | if(sfp != NULL){ 722 | if(sfp != stdin){ 723 | fclose(sfp); 724 | } 725 | sfp = NULL; 726 | } 727 | } 728 | 729 | static int select_unit_size(unsigned char *head, unsigned char *tail) 730 | { 731 | int i; 732 | int m,n,w; 733 | int count[320-188]; 734 | 735 | unsigned char *buf; 736 | 737 | buf = head; 738 | memset(count, 0, sizeof(count)); 739 | 740 | // 1st step, count up 0x47 interval 741 | while( buf+188 < tail ){ 742 | if(buf[0] != 0x47){ 743 | buf += 1; 744 | continue; 745 | } 746 | m = 320; 747 | if( buf+m > tail){ 748 | m = tail-buf; 749 | } 750 | for(i=188;isync = packet[0]; 831 | dst->transport_error_indicator = (packet[1] >> 7) & 0x01; 832 | dst->payload_unit_start_indicator = (packet[1] >> 6) & 0x01; 833 | dst->transport_priority = (packet[1] >> 5) & 0x01; 834 | dst->pid = ((packet[1] & 0x1f) << 8) | packet[2]; 835 | dst->transport_scrambling_control = (packet[3] >> 6) & 0x03; 836 | dst->adaptation_field_control = (packet[3] >> 4) & 0x03; 837 | dst->continuity_counter = packet[3] & 0x0f; 838 | } 839 | 840 | static void extract_adaptation_field(ADAPTATION_FIELD *dst, unsigned char *data) 841 | { 842 | int n; 843 | unsigned char *p; 844 | unsigned char *tail; 845 | 846 | p = data; 847 | 848 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 849 | if( (p[0] == 0) || (p[0] > 183) ){ 850 | return; 851 | } 852 | 853 | dst->adaptation_field_length = p[0]; 854 | p += 1; 855 | tail = p + dst->adaptation_field_length; 856 | if( (p+1) > tail ){ 857 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 858 | return; 859 | } 860 | 861 | dst->discontinuity_counter = (p[0] >> 7) & 1; 862 | dst->random_access_indicator = (p[0] >> 6) & 1; 863 | dst->elementary_stream_priority_indicator = (p[0] >> 5) & 1; 864 | dst->pcr_flag = (p[0] >> 4) & 1; 865 | dst->opcr_flag = (p[0] >> 3) & 1; 866 | dst->splicing_point_flag = (p[0] >> 2) & 1; 867 | dst->transport_private_data_flag = (p[0] >> 1) & 1; 868 | dst->adaptation_field_extension_flag = p[0] & 1; 869 | 870 | p += 1; 871 | 872 | if(dst->pcr_flag != 0){ 873 | if( (p+6) > tail ){ 874 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 875 | return; 876 | } 877 | dst->program_clock_reference = ((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]); 878 | dst->program_clock_reference <<= 10; 879 | dst->program_clock_reference |= (((p[4]&0x80)<<2)|((p[4]&1)<<1)|p[5]); 880 | p += 6; 881 | } 882 | 883 | if(dst->opcr_flag != 0){ 884 | if( (p+6) > tail ){ 885 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 886 | return; 887 | } 888 | dst->original_program_clock_reference = ((p[0]<<24)|(p[1]<<16)|(p[2]<<8)|p[3]); 889 | dst->original_program_clock_reference <<= 10; 890 | dst->original_program_clock_reference |= (((p[4]&0x80)<<2)|((p[4]&1)<<1)|p[5]); 891 | p += 6; 892 | } 893 | 894 | if(dst->splicing_point_flag != 0){ 895 | if( (p+1) > tail ){ 896 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 897 | return; 898 | } 899 | dst->splice_countdown = p[0]; 900 | p += 1; 901 | } 902 | 903 | if(dst->transport_private_data_flag != 0){ 904 | if( (p+1) > tail ){ 905 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 906 | return; 907 | } 908 | n = p[0]; 909 | dst->transport_private_data_length = n; 910 | p += (1+n); 911 | if( p > tail ){ 912 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 913 | return; 914 | } 915 | } 916 | 917 | if(dst->adaptation_field_extension_flag != 0){ 918 | if( (p+2) > tail ){ 919 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 920 | return; 921 | } 922 | n = p[0]; 923 | dst->adaptation_field_extension_length = n; 924 | p += 1; 925 | if( (p+n) > tail ){ 926 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 927 | return; 928 | } 929 | dst->ltw_flag = (p[0] >> 7) & 1; 930 | dst->piecewise_rate_flag = (p[0] >> 6) & 1; 931 | dst->seamless_splice_flag = (p[0] >> 5) & 1; 932 | p += 1; 933 | n -= 1; 934 | if(dst->ltw_flag != 0){ 935 | if(n < 2){ 936 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 937 | return; 938 | } 939 | dst->ltw_valid_flag = (p[0] >> 7) & 1; 940 | dst->ltw_offset = (((p[0] & 0x7f)<<8) | p[1]); 941 | p += 2; 942 | n -= 2; 943 | } 944 | if(dst->piecewise_rate_flag != 0){ 945 | if(n < 3){ 946 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 947 | return; 948 | } 949 | dst->piecewise_rate = (((p[0] & 0x3f)<<16)|(p[1]<<8)|p[2]); 950 | p += 3; 951 | n -= 3; 952 | } 953 | if(dst->seamless_splice_flag != 0){ 954 | if(n < 5){ 955 | memset(dst, 0, sizeof(ADAPTATION_FIELD)); 956 | return; 957 | } 958 | dst->splice_type = (p[0] >> 4) & 0x0f; 959 | dst->dts_next_au = (((p[0]&0x0e)<<14)|(p[1]<<7)|((p[2]>>1)&0x7f)); 960 | dst->dts_next_au <<= 15; 961 | dst->dts_next_au |= ((p[3]<<7)|((p[4]>>1)&0x7f)); 962 | p += 5; 963 | n -= 5; 964 | } 965 | p += n; 966 | } 967 | 968 | } 969 | 970 | static int check_unit_invert(unsigned char *head, unsigned char *tail) 971 | { 972 | unsigned char *buf; 973 | 974 | buf = tail-188; 975 | 976 | while(head <= buf){ 977 | if(buf[0] == 0x47){ 978 | return tail-buf; 979 | } 980 | buf -= 1; 981 | } 982 | 983 | return 0; 984 | } 985 | 986 | static void add_drop_info(RESYNC_REPORT *report, int count, int pid, int64_t pos) 987 | { 988 | int idx; 989 | int n; 990 | 991 | idx = count - 1; 992 | if( (report == NULL) || (idx < 0) ){ 993 | // do nothing 994 | return; 995 | } 996 | 997 | if(report[idx].drop_count < 4){ 998 | n = (int) report[idx].drop_count; 999 | report[idx].drop_pid[n] = (short)pid; 1000 | report[idx].drop_pos[n] = pos; 1001 | } 1002 | 1003 | report[idx].drop_count += 1; 1004 | } 1005 | 1006 | static void print_resync_report(RESYNC_REPORT *report, int count) 1007 | { 1008 | int i,j; 1009 | int m,n; 1010 | int year,month,date; 1011 | 1012 | printf("total sync error: %d\n", count); 1013 | 1014 | m = count; 1015 | if(report == NULL){ 1016 | m = 0; 1017 | } 1018 | 1019 | for(i=0;i 4){ 1041 | n = 4; 1042 | } 1043 | for(j=0;jlast_mjd = mjd; 1052 | report->last_h = h; 1053 | report->last_m = m; 1054 | report->last_s = s; 1055 | } 1056 | 1057 | static void update_resync_report_time(RESYNC_REPORT *report, int count, int mjd, int h, int m, int s) 1058 | { 1059 | int i; 1060 | 1061 | for(i = count - 1; report && i >= 0 && !report[i].mjd; i--){ 1062 | report[i].mjd = mjd; 1063 | report[i].h = h; 1064 | report[i].m = m; 1065 | report[i].s = s; 1066 | } 1067 | } 1068 | 1069 | static void mjd_to_ymd(int mjd, int *y, int *m, int *d) 1070 | { 1071 | int yd = (mjd * 20 - 301564) / 7305; 1072 | int md = (mjd * 10000 - 149561000 - yd * 1461 / 4 * 10000) / 306001; 1073 | int k = (md == 14 || md == 15) ? 1 : 0; 1074 | 1075 | *y = yd + k + 1900; 1076 | *m = md - 1 - k * 12; 1077 | *d = mjd - 14956 - yd * 1461 / 4 - md * 306001 / 10000; 1078 | } 1079 | 1080 | static int find_packet_time_data(unsigned char **time_data, const TS_HEADER *hdr, unsigned char *packet) 1081 | { 1082 | unsigned char *p; 1083 | 1084 | int table_id; 1085 | int length; 1086 | 1087 | p = packet + 4; 1088 | if(hdr->adaptation_field_control & 0x02){ 1089 | if(p[0] > 182){ 1090 | return 0; 1091 | } 1092 | /* adaptation length */ 1093 | p += (p[0]+1); 1094 | } 1095 | if(hdr->payload_unit_start_indicator == 0){ 1096 | /* do nothing */ 1097 | return 0; 1098 | } 1099 | if((int)(p - packet) + p[0] > 184){ 1100 | return 0; 1101 | } 1102 | /* pointer */ 1103 | p += (p[0]+1); 1104 | 1105 | table_id = p[0]; 1106 | length = ((p[1]<<8)|p[2]) & 0x0fff; 1107 | p += 3; 1108 | if(length < 5 || (int)(p - packet) + 5 > 188){ 1109 | return 0; 1110 | } 1111 | 1112 | *time_data = p; 1113 | return table_id; 1114 | } 1115 | 1116 | static void show_tdt_or_tot(TS_HEADER *hdr, unsigned char *packet, int64_t pos) 1117 | { 1118 | unsigned char *p; 1119 | int table_id = find_packet_time_data(&p, hdr, packet); 1120 | 1121 | if(table_id == 0x70){ 1122 | /* TDT */ 1123 | fprintf(stdout, "TDT: [%02x:%02x:%02x] offset=%"PRId64"\n", p[2], p[3], p[4], pos); 1124 | }else if(table_id == 0x73){ 1125 | /* TOT */ 1126 | fprintf(stdout, "TOT: [%02x:%02x:%02x] offset=%"PRId64"\n", p[2], p[3], p[4], pos); 1127 | } 1128 | } 1129 | 1130 | --------------------------------------------------------------------------------