Mercurial > libavformat.hg
comparison mpegts.c @ 170:0543d27721c1 libavformat
cosmetic change in resync code - added PAT scanning code if no SDT is found (in the futur it would be interesting to give an API to change channel - also useful for DV input number or TV grab tunning
author | bellard |
---|---|
date | Tue, 15 Jul 2003 13:21:39 +0000 |
parents | e4d2f704bf80 |
children | a313e1080322 |
comparison
equal
deleted
inserted
replaced
169:7c084ad75a99 | 170:0543d27721c1 |
---|---|
21 #include "mpegts.h" | 21 #include "mpegts.h" |
22 | 22 |
23 //#define DEBUG_SI | 23 //#define DEBUG_SI |
24 | 24 |
25 /* 1.0 second at 24Mbit/s */ | 25 /* 1.0 second at 24Mbit/s */ |
26 #define MAX_SCAN_PACKETS 16000 | 26 #define MAX_SCAN_PACKETS 32000 |
27 | |
28 /* maximum size in which we look for synchronisation if | |
29 synchronisation is lost */ | |
30 #define MAX_RESYNC_SIZE 4096 | |
27 | 31 |
28 static int add_pes_stream(AVFormatContext *s, int pid); | 32 static int add_pes_stream(AVFormatContext *s, int pid); |
29 | 33 |
30 enum MpegTSFilterType { | 34 enum MpegTSFilterType { |
31 MPEGTS_PES, | 35 MPEGTS_PES, |
32 MPEGTS_SECTION, | 36 MPEGTS_SECTION, |
33 }; | 37 }; |
34 | 38 |
35 /* XXX: suppress 'pkt' parameter */ | |
36 typedef void PESCallback(void *opaque, const uint8_t *buf, int len, int is_start); | 39 typedef void PESCallback(void *opaque, const uint8_t *buf, int len, int is_start); |
37 | 40 |
38 typedef struct MpegTSPESFilter { | 41 typedef struct MpegTSPESFilter { |
39 PESCallback *pes_cb; | 42 PESCallback *pes_cb; |
40 void *opaque; | 43 void *opaque; |
430 printf("sid=0x%x pid=0x%x\n", sid, pmt_pid); | 433 printf("sid=0x%x pid=0x%x\n", sid, pmt_pid); |
431 #endif | 434 #endif |
432 if (sid == 0x0000) { | 435 if (sid == 0x0000) { |
433 /* NIT info */ | 436 /* NIT info */ |
434 } else { | 437 } else { |
435 if (ts->req_sid == sid || ts->req_sid < 0) { | 438 if (ts->req_sid == sid) { |
436 ts->pmt_filter = mpegts_open_section_filter(ts, pmt_pid, | 439 ts->pmt_filter = mpegts_open_section_filter(ts, pmt_pid, |
437 pmt_cb, ts, 1); | 440 pmt_cb, ts, 1); |
438 goto found; | 441 goto found; |
439 } | 442 } |
440 } | 443 } |
441 } | 444 } |
442 /* not found */ | 445 /* not found */ |
443 ts->set_service_cb(ts->set_service_opaque, -1); | 446 ts->set_service_cb(ts->set_service_opaque, -1); |
444 | 447 |
445 found: | 448 found: |
449 mpegts_close_filter(ts, ts->pat_filter); | |
450 ts->pat_filter = NULL; | |
451 } | |
452 | |
453 /* add all services found in the PAT */ | |
454 static void pat_scan_cb(void *opaque, const uint8_t *section, int section_len) | |
455 { | |
456 MpegTSContext *ts = opaque; | |
457 SectionHeader h1, *h = &h1; | |
458 const uint8_t *p, *p_end; | |
459 int sid, pmt_pid; | |
460 char *provider_name, *name; | |
461 char buf[256]; | |
462 | |
463 #ifdef DEBUG_SI | |
464 printf("PAT:\n"); | |
465 av_hex_dump((uint8_t *)section, section_len); | |
466 #endif | |
467 p_end = section + section_len - 4; | |
468 p = section; | |
469 if (parse_section_header(h, &p, p_end) < 0) | |
470 return; | |
471 if (h->tid != PAT_TID) | |
472 return; | |
473 | |
474 for(;;) { | |
475 sid = get16(&p, p_end); | |
476 if (sid < 0) | |
477 break; | |
478 pmt_pid = get16(&p, p_end) & 0x1fff; | |
479 if (pmt_pid < 0) | |
480 break; | |
481 #ifdef DEBUG_SI | |
482 printf("sid=0x%x pid=0x%x\n", sid, pmt_pid); | |
483 #endif | |
484 if (sid == 0x0000) { | |
485 /* NIT info */ | |
486 } else { | |
487 /* add the service with a dummy name */ | |
488 snprintf(buf, sizeof(buf), "Service %x\n", sid); | |
489 name = av_strdup(buf); | |
490 provider_name = av_strdup(""); | |
491 if (name && provider_name) { | |
492 new_service(ts, sid, provider_name, name); | |
493 } else { | |
494 av_freep(&name); | |
495 av_freep(&provider_name); | |
496 } | |
497 } | |
498 } | |
499 ts->stop_parse = 1; | |
500 | |
501 /* remove filter */ | |
446 mpegts_close_filter(ts, ts->pat_filter); | 502 mpegts_close_filter(ts, ts->pat_filter); |
447 ts->pat_filter = NULL; | 503 ts->pat_filter = NULL; |
448 } | 504 } |
449 | 505 |
450 void mpegts_set_service(MpegTSContext *ts, int sid, | 506 void mpegts_set_service(MpegTSContext *ts, int sid, |
531 /* remove filter */ | 587 /* remove filter */ |
532 mpegts_close_filter(ts, ts->sdt_filter); | 588 mpegts_close_filter(ts, ts->sdt_filter); |
533 ts->sdt_filter = NULL; | 589 ts->sdt_filter = NULL; |
534 } | 590 } |
535 | 591 |
536 /* scan services an a transport stream by looking at the sdt */ | 592 /* scan services in a transport stream by looking at the SDT */ |
537 void mpegts_scan_sdt(MpegTSContext *ts) | 593 void mpegts_scan_sdt(MpegTSContext *ts) |
538 { | 594 { |
539 ts->sdt_filter = mpegts_open_section_filter(ts, SDT_PID, | 595 ts->sdt_filter = mpegts_open_section_filter(ts, SDT_PID, |
540 sdt_cb, ts, 1); | 596 sdt_cb, ts, 1); |
541 } | 597 } |
542 | 598 |
599 /* scan services in a transport stream by looking at the PAT (better | |
600 than nothing !) */ | |
601 void mpegts_scan_pat(MpegTSContext *ts) | |
602 { | |
603 ts->pat_filter = mpegts_open_section_filter(ts, PAT_PID, | |
604 pat_scan_cb, ts, 1); | |
605 } | |
543 | 606 |
544 /* TS stream handling */ | 607 /* TS stream handling */ |
545 | 608 |
546 enum MpegTSState { | 609 enum MpegTSState { |
547 MPEGTS_HEADER = 0, | 610 MPEGTS_HEADER = 0, |
793 } | 856 } |
794 } else { | 857 } else { |
795 if (cc_ok) { | 858 if (cc_ok) { |
796 write_section_data(s, tss, | 859 write_section_data(s, tss, |
797 p, p_end - p, 0); | 860 p, p_end - p, 0); |
798 } | 861 } |
799 } | 862 } |
800 } else { | 863 } else { |
801 tss->u.pes_filter.pes_cb(tss->u.pes_filter.opaque, | 864 tss->u.pes_filter.pes_cb(tss->u.pes_filter.opaque, |
802 p, p_end - p, is_start); | 865 p, p_end - p, is_start); |
803 } | 866 } |
804 } | 867 } |
805 | 868 |
869 /* XXX: try to find a better synchro over several packets (use | |
870 get_packet_size() ?) */ | |
871 static int mpegts_resync(AVFormatContext *s) | |
872 { | |
873 ByteIOContext *pb = &s->pb; | |
874 int c, i; | |
875 | |
876 for(i = 0;i < MAX_RESYNC_SIZE; i++) { | |
877 c = url_fgetc(pb); | |
878 if (c < 0) | |
879 return -1; | |
880 if (c == 0x47) { | |
881 url_fseek(pb, -1, SEEK_CUR); | |
882 return 0; | |
883 } | |
884 } | |
885 /* no sync found */ | |
886 return -1; | |
887 } | |
888 | |
806 static int handle_packets(AVFormatContext *s, int nb_packets) | 889 static int handle_packets(AVFormatContext *s, int nb_packets) |
807 { | 890 { |
808 MpegTSContext *ts = s->priv_data; | 891 MpegTSContext *ts = s->priv_data; |
809 ByteIOContext *pb = &s->pb; | 892 ByteIOContext *pb = &s->pb; |
810 uint8_t packet[TS_FEC_PACKET_SIZE]; | 893 uint8_t packet[TS_FEC_PACKET_SIZE]; |
811 int packet_num, len; | 894 int packet_num, len; |
812 int i, found = 0; | |
813 int64_t pos; | 895 int64_t pos; |
814 | 896 |
815 ts->stop_parse = 0; | 897 ts->stop_parse = 0; |
816 packet_num = 0; | 898 packet_num = 0; |
817 for(;;) { | 899 for(;;) { |
823 pos = url_ftell(pb); | 905 pos = url_ftell(pb); |
824 len = get_buffer(pb, packet, ts->raw_packet_size); | 906 len = get_buffer(pb, packet, ts->raw_packet_size); |
825 if (len != ts->raw_packet_size) | 907 if (len != ts->raw_packet_size) |
826 return AVERROR_IO; | 908 return AVERROR_IO; |
827 /* check paquet sync byte */ | 909 /* check paquet sync byte */ |
828 if (packet[0] != 0x47) | 910 if (packet[0] != 0x47) { |
829 { | 911 /* find a new packet start */ |
830 //printf("bad packet: 0x%x\n", packet[0]); | 912 url_fseek(pb, -ts->raw_packet_size, SEEK_CUR); |
831 found = 0; | 913 if (mpegts_resync(s) < 0) |
832 for (i = 0; i < ts->raw_packet_size; i++) | 914 return AVERROR_INVALIDDATA; |
833 { | 915 else |
834 if (packet[i] == 0x47) | 916 continue; |
835 { | |
836 found = 1; | |
837 //printf("packet start at: %d\n", i); | |
838 break; | |
839 } | |
840 } | |
841 | |
842 if (found) | |
843 { | |
844 url_fseek(pb, pos + i, SEEK_SET); | |
845 continue; | |
846 } | |
847 return AVERROR_INVALIDDATA; | |
848 } | 917 } |
849 handle_packet(s, packet); | 918 handle_packet(s, packet); |
850 } | 919 } |
851 return 0; | 920 return 0; |
852 } | 921 } |
853 | 922 |
854 static int mpegts_probe(AVProbeData *p) | 923 static int mpegts_probe(AVProbeData *p) |
855 { | 924 { |
925 #if 1 | |
856 int size; | 926 int size; |
857 size = get_packet_size(p->buf, p->buf_size); | 927 size = get_packet_size(p->buf, p->buf_size); |
858 if (size < 0) | 928 if (size < 0) |
859 return 0; | 929 return 0; |
860 return AVPROBE_SCORE_MAX - 1; | 930 return AVPROBE_SCORE_MAX - 1; |
931 #else | |
932 /* only use the extension for safer guess */ | |
933 if (match_ext(p->filename, "ts")) | |
934 return AVPROBE_SCORE_MAX; | |
935 else | |
936 return 0; | |
937 #endif | |
861 } | 938 } |
862 | 939 |
863 void set_service_cb(void *opaque, int ret) | 940 void set_service_cb(void *opaque, int ret) |
864 { | 941 { |
865 MpegTSContext *ts = opaque; | 942 MpegTSContext *ts = opaque; |
871 AVFormatParameters *ap) | 948 AVFormatParameters *ap) |
872 { | 949 { |
873 MpegTSContext *ts = s->priv_data; | 950 MpegTSContext *ts = s->priv_data; |
874 ByteIOContext *pb = &s->pb; | 951 ByteIOContext *pb = &s->pb; |
875 uint8_t buf[1024]; | 952 uint8_t buf[1024]; |
876 int len; | 953 int len, sid; |
877 int64_t pos; | 954 int64_t pos; |
878 MpegTSService *service; | 955 MpegTSService *service; |
879 | 956 |
880 /* read the first 1024 bytes to get packet size */ | 957 /* read the first 1024 bytes to get packet size */ |
881 pos = url_ftell(pb); | 958 pos = url_ftell(pb); |
886 if (ts->raw_packet_size <= 0) | 963 if (ts->raw_packet_size <= 0) |
887 goto fail; | 964 goto fail; |
888 ts->auto_guess = 0; | 965 ts->auto_guess = 0; |
889 | 966 |
890 if (!ts->auto_guess) { | 967 if (!ts->auto_guess) { |
891 int sid = -1; | |
892 ts->set_service_ret = -1; | 968 ts->set_service_ret = -1; |
893 | 969 |
894 /* first do a scaning to get all the services */ | 970 /* first do a scaning to get all the services */ |
895 url_fseek(pb, pos, SEEK_SET); | 971 url_fseek(pb, pos, SEEK_SET); |
896 mpegts_scan_sdt(ts); | 972 mpegts_scan_sdt(ts); |
973 | |
974 handle_packets(s, MAX_SCAN_PACKETS); | |
975 | |
976 if (ts->nb_services <= 0) { | |
977 /* no SDT found, we try to look at the PAT */ | |
978 | |
979 url_fseek(pb, pos, SEEK_SET); | |
980 mpegts_scan_pat(ts); | |
981 | |
982 handle_packets(s, MAX_SCAN_PACKETS); | |
983 } | |
897 | 984 |
898 handle_packets(s, MAX_SCAN_PACKETS); | 985 if (ts->nb_services <= 0) |
899 | 986 return -1; |
900 if (ts->nb_services > 0) | 987 |
901 { | 988 /* tune to first service found */ |
902 /* tune to first service found */ | 989 service = ts->services[0]; |
903 service = ts->services[0]; | 990 sid = service->sid; |
904 sid = service->sid; | 991 #ifdef DEBUG_SI |
905 #ifdef DEBUG_SI | 992 printf("tuning to '%s'\n", service->name); |
906 printf("tuning to '%s'\n", service->name); | 993 #endif |
907 #endif | |
908 } | |
909 | 994 |
910 /* now find the info for the first service if we found any, | 995 /* now find the info for the first service if we found any, |
911 otherwise try to filter all PATs */ | 996 otherwise try to filter all PATs */ |
912 | 997 |
913 url_fseek(pb, pos, SEEK_SET); | 998 url_fseek(pb, pos, SEEK_SET); |