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);