[mythtv] Latest cvs - atscstreamdata.cpp - PSIP packet failed CRC check

Eric Anderson rico99 at sbcglobal.net
Wed Jan 19 03:24:53 EST 2005


Hi all  -

Here's a different patch for this. I finally got around to figuring 
this out. (Took
a while to understand some of the code.)

Essentially the problem here is that the PES code doesn't compute the 
CRC
for multi-packet ETT and EIT tables. In fact, for the program text 
tables you
often will have data that spans multiple packets. For the tables that 
are interesting
to the current code, single packets are sufficient. And it's good to 
check those
CRC's -- so if you get a bad packet off of the air, we don't go and 
corrupt the
PMAP table, etc..., that kind of thing.

But to really check the ETT/EIT tables properly you have to assemble
all of the packets together. And I don't think the code currently is 
doing
that. Fine. But it's reporting errors! To someone who doesn't understand
the code, they think there's a problem somewhere. Can we improve this?

Either:
    1. If we're not putting together all of the required data covered by
    the CRC, maybe we shouldn't perform a CRC check.

OR...
    2. We have to put together the full data before checking the CRC.

Since the ETT/EIT are being ignored now anyway, how about going with
option #1 -- not computing a CRC if we don't have all of the data. The
attached diffs provide a simple patch to 'pespacket.h' that fixes this. 
Unfortunately
I don't have the time to implement option #2.

On a different subject, while debugging this code, I hit an assert in 
the
atsctables.cpp. I *think* the assert is saying -- "If we see table data 
for
NTSC in an ATSC PSIP packet, that doesn't make sense." Well, fine.
Except somehow I still hit it and there went my backend. Not fun. And 
this
was all in toString() code that was simply going to be part of a debug 
message.
So in the diffs I've also included a change to atsctables.cpp where I
change the assert to return a (semi-)informative error message instead.

Finally, I'm also attaching a sample binary file that's 4 TS packets 
long. If you
feed this into the PSIP code, you'll get this with the latest CVS:

   2005-01-19 00:10:41.374 PSIP packet failed CRC check

This error goes away with the patch applied.

I'm also attaching a short parser program that demonstrates that this
packet sequence actually contains valid PSIP data. (Warning: this parser
assumes it will get consecutive packets for the same PID. In my test
environment I've been making sure of this through various means.)If you
run it on the sample data you will get:

> % ./psip_parse data1.s
> Pkt: pid=0ffb tid=c7 len=0d4 tid_ext=0000 [Channel: srcid=0012 
> (0=0000)]
> adapt:0  payload:1
>
> Pkt: pid=0e02 tid=cc len=0b8 tid_ext=6788 [Event: srcid=0001 
> evntid=015f]
> adapt:0  payload:1
> Pkt: pid=0e02 tid=cc
> Got whole packet
> Good CRC!
> ETT packet
> 1 strings
> Lang: eng
> String (a2 bytes): 'Trey Anastasio Jam band icon Trey Anastasio, 
> former frontman of Phish, goes solo. With his skillful improvisation, 
> he performs pieces from his first solo release.'

Regards.

-Eric

-------------- next part --------------
A non-text attachment was scrubbed...
Name: diffs
Type: application/octet-stream
Size: 1903 bytes
Desc: not available
Url : http://mythtv.org/pipermail/mythtv-dev/attachments/20050119/4b546f04/diffs.obj
-------------- next part --------------
  
   
-------------- next part --------------
A non-text attachment was scrubbed...
Name: data1.s
Type: application/octet-stream
Size: 753 bytes
Desc: not available
Url : http://mythtv.org/pipermail/mythtv-dev/attachments/20050119/4b546f04/data1.obj
-------------- next part --------------
  
   
-------------- next part --------------
#include <stdio.h>
#include <qstring.h>
#include <stdio.h>

#define PKTSIZE 188

typedef unsigned char uchar_t;

extern "C" int mpegts_crc32(const uchar_t *buf, int len);


main(int argc, char *argv[])
{
    uchar_t s[PKTSIZE];
    FILE *f = stdin;
    int cnt;
    int i,j,k,l;

    uchar_t eitbuf[8192];
    uchar_t ettbuf[8192];
    int eit_idx = 0;
    int ett_idx = 0;
    uchar_t *t;
    int tid = 0;
    int pid;
    int len;
    int tid_ext;
    int etm_id;
    int haspayload, payloadstart;
    int hasadaptationfield;

    int eit_source_id;
    int eit_version;
    int eit_current_next_indicator;
    int eit_section;
    int eit_last_section;
    int eit_protocol_version;
    int eit_num_events_in_section;

    if (argc > 1) {
	f = fopen(argv[1],"r");
	if (!f) {
	    perror("fopen failed");
	    exit(-1);
	}
    }

    while (1) {

	cnt = fread(s, PKTSIZE, 1, f);
	if (!cnt) break;

	pid = ((s[1] & 0xf) << 8) | (s[2] << 0);

	haspayload = (s[3] & 0x10) ? 1 : 0;
	payloadstart = (s[1] & 0x40) ? 1 : 0;
	hasadaptationfield = (s[3] & 0x20) ? 1 : 0;

	// Bit [5] indicates start??
	if (payloadstart) {
	    tid = s[5];
	    len = ((s[6] & 0xf) << 8) | (s[7] << 0);
	    tid_ext = (s[8] << 8) | (s[9] << 0);
	    etm_id = (s[14] << 24) | (s[15] << 16) | (s[16] << 8) | (s[17] << 0);
	    printf("Pkt: pid=%04x tid=%02x len=%03x ", 
		   pid, tid, len);
	    printf("tid_ext=%04x ",tid_ext);

	    if (etm_id & 0x2) {
		printf("[Event: srcid=%04x evntid=%04x] \n", 
		       (etm_id >> 16), ((etm_id >> 2) & 0x3fff));
	    } else {
		printf("[Channel: srcid=%04x (0=%04x)] \n",
		       (etm_id >> 16), ((etm_id >> 2) & 0x3fff));
	    }
	    printf("adapt:%d  payload:%d\n", hasadaptationfield, haspayload);

	    switch (tid) {
	    case 0xCB:
		eit_idx = 0;
		for (i=0;i<PKTSIZE-5;i++) {
		    eitbuf[eit_idx++] = s[i+5];
		}
		break;
	    case 0xCC:
		ett_idx = 0;
		for (i=0;i<PKTSIZE-5;i++) {
		    ettbuf[ett_idx++] = s[i+5];
		}
		break;
	    }

	} else {
	    // Assume tid is still valid from last time
	    switch (tid) {
	    case 0xCB:
		if (eit_idx > 4096) {
		    printf("Too big of an EIT!!\n");
		    eit_idx = 0;
		    tid = 0;
		    break;
		}
		for (i=0;i<PKTSIZE-4;i++) {
		    eitbuf[eit_idx++] = s[i+4];
		}
		printf("Pkt: pid=%04x tid=%02x\n", pid, tid);
		break;
	    case 0xCC:
		if (ett_idx > 4096) {
		    printf("Too big of an ETT!!\n");
		    ett_idx = 0;
		    tid = 0;
		    break;
		}
		for (i=0;i<PKTSIZE-4;i++) {
		    ettbuf[ett_idx++] = s[i+4];
		}
		printf("Pkt: pid=%04x tid=%02x\n", pid, tid);
		break;
	    }
	}

	// Got whole thing?
	int whole = 0;
	uchar_t *buf = NULL;
	int crc = -1;

	switch (tid) {
	case 0xCB:
	    buf = eitbuf;
	    if ((eit_idx != 0) && (eit_idx >= len + 4)) {
		whole = 1;
	    }
	    break;
	case 0xCC:
	    buf = ettbuf;
	    if ((ett_idx != 0) && (ett_idx >= len + 4)) {
		whole = 1;
	    }
	    break;
	}

	if (whole) {
	    printf("Got whole packet\n");
	    
	    // Check CRC
	    if (buf) crc = mpegts_crc32(buf, len+3);
	    if (crc == 0) {
		printf("Good CRC!\n");
	    } else {
		printf("Bad CRC! (%08x)\n", crc);
	    }

	    // Parse packet fields
	    switch (tid) {
	    case 0xCB:
		printf("EIT packet\n");

		t = eitbuf+3;

		eit_source_id = (t[0] << 8) | (t[1] << 0); 
		t+=2;
		eit_version = (*t >> 1) & 0x1f;
		eit_current_next_indicator = (*t++ & 0x01);
		eit_section = *t++;
		eit_last_section = *t++;
		eit_protocol_version = *t++;
		eit_num_events_in_section = *t++;

		printf("Src id: %04x\n", eit_source_id);
		printf("Version: %02x\n", eit_version);
		printf("CNI: %x\n", eit_current_next_indicator);
		printf("Section: %02x (last=%02x)\n", eit_section, eit_last_section);
		printf("Protocol version: %02x\n", eit_protocol_version);
		printf("Events: %02x\n", eit_num_events_in_section);

		for (i=0;i<eit_num_events_in_section;i++) {

		    int eit_event_id = ((t[0] & 0x3f) << 8) | (t[1] << 0);
		    t+=2;
		    time_t eit_start_time = (t[0] << 24) | (t[1] << 16) | (t[2] << 8) | (t[3] << 0);
		    t+=4;
		    int eit_etm_location = (*t >> 4) & 0x3;
		    int eit_length_seconds = ((t[0] & 0xf) << 16) | (t[1] << 8) | (t[2] << 0);
		    t+=3;
		    int eit_length_minutes = (eit_length_seconds / 60);
		    int eit_length_hours = (eit_length_seconds / 3600);
		    int eit_title_length = *t++;

		    printf("Event %d - \n", i);
		    printf("   event_id = %04x\n", eit_event_id);
		    printf("   event_start_time = %s", ctime(&eit_start_time));
		    printf("   etm_location = %x\n", eit_etm_location);
		    printf("   event_run_time = %02d:%02d:%02d (%x)\n", 
			   eit_length_hours, 
			   eit_length_minutes - (eit_length_hours * 60),
			   eit_length_seconds - (eit_length_minutes * 60),
			   eit_length_seconds);

		    int eit_num_strings = *t++;
		    printf("%d strings\n", eit_num_strings);
		    for (j=0;j<eit_num_strings;j++) {
			printf("Lang: %c%c%c\n", t[0],t[1],t[2]);
			t+=3;
			int eit_num_segs = *t++;
			for (k=0;k<eit_num_segs;k++) {
			    int comp_type = *t++;
			    int comp_mode = *t++;
			    //printf("Comp-type:%02x Mode:%02x\n", comp_type, comp_mode);
			    int eit_num_bytes = *t++;
			    printf("Title (%02x bytes): '", eit_num_bytes);
			    for (l=0;l<eit_num_bytes;l++) {
				printf("%c",*t++);
			    }
			    printf("'\n");
			}
		    }
		    //		    char eit_title[257];
		    //		    for (j=0;j<eit_title_length;j++) {
		    //			eit_title[j] = *t++;
		    //		    }
		    //		    // NULL Terminate
		    //		    eit_title[j] = 0;

		    char eit_descriptor_length = ((t[0] & 0xf) << 8) | (t[1] << 0);
		    t+=2;

		    int descriptor_tag;
		    int descriptor_length;
		    int descriptor_ac3_sample_rate_code;
		    int descriptor_ac3_bsid;
		    int descriptor_ac3_bit_rate_code;
		    int descriptor_ac3_surround_mode;
		    int descriptor_ac3_bsmod;
		    int descriptor_ac3_num_channels;
		    int descriptor_ac3_full_service;

		    int ac3_sample_rate_map[8] = { 1, 2, 4, 0,
						       3, 5, 6, 7 };
		    char *ac3_sample_rates[3] = { "48", "44.1", "32" };

		    for (j=0;j<eit_descriptor_length;) {
			int descriptor_tag = t[j++];
			int descriptor_length = t[j++];
			int xx,space=0;

			switch (descriptor_tag) {

			// AC-3 Audio?
			case 0x81:
			    descriptor_ac3_sample_rate_code = (t[j+0] >> 5) & 0x7;
			    descriptor_ac3_bsid = (t[j+0] & 0x1f);
			    descriptor_ac3_bit_rate_code = (t[j+1] >> 2) & 0x3f;
			    descriptor_ac3_surround_mode = (t[j+1] & 0x3);
			    descriptor_ac3_bsmod = (t[j+2] >> 5) & 0x7;
			    descriptor_ac3_num_channels = (t[j+2] >> 1) & 0xf;
			    descriptor_ac3_full_service = (t[j+2] & 0x1);
			    printf("AC3 - Rates: [");
			    for (xx=0;xx<3;xx++) {
				int map = ac3_sample_rate_map[descriptor_ac3_sample_rate_code];
				if (map & (1 << xx)) {
				    if (space) printf(" ");
				    printf("%s",ac3_sample_rates[xx]);
				}
			    }
			    printf("] ");
			    printf("Surround=%d ", descriptor_ac3_surround_mode);
			    printf("Bsmod=%d ", descriptor_ac3_bsmod);
			    printf("Chan=%d ", descriptor_ac3_num_channels);
			    printf("FS=%d\n", descriptor_ac3_full_service);
			    break;

			// Caption Service?
			case 0x86:
			    printf("%02x - Caption service\n", descriptor_tag);
			    break;

			// Content Advisory?
			case 0x87:
			    printf("%02x - Content Advisory\n", descriptor_tag);
			    break;

			default:
			    break;
			}
			j += descriptor_length;
		    }
		    t+=eit_descriptor_length;
		}
		eit_idx = 0;
		printf("\n");
		break;

	    case 0xCC:
		printf("ETT packet\n");

		t = ettbuf+13;
		int ett_str_cnt = *t++;
		printf("%d strings\n", ett_str_cnt);
		for (i=0;i<ett_str_cnt;i++) {
		    printf("Lang: %c%c%c\n", t[0],t[1],t[2]);
		    t+=3;
		    int ett_num_segs = *t++;
		    for (j=0;j<ett_num_segs;j++) {
			int comp_type = *t++;
			int comp_mode = *t++;
			//printf("Comp-type:%02x Mode:%02x\n", comp_type, comp_mode);
			int ett_num_bytes = *t++;
			printf("String (%02x bytes): '", ett_num_bytes);
			for (k=0;k<ett_num_bytes;k++) {
			    printf("%c",*t++);
			}
			printf("'\n\n");
		    }
		}
		ett_idx = 0;
	    }
	}
    }
}
-------------- next part --------------





More information about the mythtv-dev mailing list