Re: [PATCH 1/3] gspca pac7302/pac7311: simplify pac_find_sof

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Theodore Kilgore írta:
> 
> On Mon, 2 Nov 2009, Németh Márton wrote:
> 
>> Theodore Kilgore wrote:
>>> On Sun, 1 Nov 2009, Németh Márton wrote:
>>>> Remove struct sd dependency from pac_find_sof() function implementation.
>>>> This step prepares separation of pac7302 and pac7311 specific parts of
>>>> struct sd.
>>> [...]
>>> But here is the point. The sn9c2028 cameras have a structure which seems
>>> similar to the mr97310a cameras. They use a similar decompression
>>> algorithm. They have a similar frame header. Specifically, the sn9c2028
>>> frame header starts with the five bytes
>>>
>>>                  0xff, 0xff, 0x00, 0xc4, 0xc4
>>>
>>> whereas the pac_common frame header starts with the five bytes
>>>
>>>                  0xff, 0xff, 0x00, 0xff, 0x96
>>>
>>> Right now, for my own use, I have written a file sn9c2028.h which
>>> essentially duplicates the functionality of pac_common.h and contains a
>>> function which searches for the sn9c2028 SOF marker instead of searching
>>> for the pac SOF marker. Is this necessarily the good, permanent solution?
>>> I am not so sure about that.
>> I think the pac_find_sof() is a special case. To find a SOF sequence in
>> a bigger buffer in general needs to first analyze the SOF sequence for
>> repeated bytes. If there are repeated bytes the search have to be
>> continued in a different way, see the state machine currently in the
>> pac_common.h. To find the sn9c2028 frame header a different state machine
>> is needed. It might be possible to implement a search function which
>> can find any SOF sequence but I am afraid that this algorithm would be
>> too complicated because of the search string analysis.
> 
> Well, I do not really know enough about this to be able to say something 
> authoritative, but:
> 
> 1. There is an obvious limitation on the length of the SOF marker. If it 
> is agreed upon that the SOF marker is 5 bytes or less, then it ought not 
> to be so terrible a thing to do. Namely, your state machine should accept 
> an input, consisting of a pointer to the proper SOF marker and use that 
> one instead of what is "hard wired" in your code. So, for example,
> 
>                  switch (sd->sof_read) {
>                  case 0:
>                          if (m[i] == 0xff)
>                                  sd->sof_read = 1;
>                          break;
>                  case 1:
>                          if (m[i] == 0xff)
>                                  sd->sof_read = 2;
>                          else
>                                  sd->sof_read = 0;
>                          break;
>  			(and so on)
> 
> could read instead as
> 
>                  switch (sd->sof_read) {
>                  case 0:
>                          if (m[i] == sof_marker[0])
>                                  sd->sof_read = 1;
>                          break;
>                  case 1:
>                          if (m[i] == sof_marker[1])
>                                  sd->sof_read = 2;
>                          else
>                                  sd->sof_read = 0;
>                          break;
>  			(and so on)
> 
> 
> The problem would come if the SOF marker were six bytes long instead. The 
> way to solve that would be to figure out what is the longest SOF marker 
> that one wants to deal with, beforehand. I am not sure what is the 
> prevailing number of bytes in such an SOF marker, or the maximum number. 
> But it would be possible to prescribe some reasonable maximum number 
> and take that into account, I think.

I am afraid you missed an important point: the state machine depends on the
*contents* of the SOF marker:

>From pac_common.h:

   The following state machine finds the SOF marker sequence
   0xff, 0xff, 0x00, 0xff, 0x96 in a byte stream.

           +----------+
           | 0: START |<---------------\
           +----------+<-\             |
             |       \---/otherwise    |
             v 0xff                    |
           +----------+ otherwise      |
           |     1    |--------------->*
           |          |                ^
           +----------+                |
             |                         |
             v 0xff                    |
           +----------+<-\0xff         |
        /->|          |--/             |
        |  |     2    |--------------->*
        |  |          | otherwise      ^
        |  +----------+                |
        |    |                         |
        |    v 0x00                    |
        |  +----------+                |
        |  |     3    |                |
        |  |          |--------------->*
        |  +----------+ otherwise      ^
        |    |                         |
   0xff |    v 0xff                    |
        |  +----------+                |
        \--|     4    |                |
           |          |----------------/
           +----------+ otherwise
             |
             v 0x96
           +----------+
           |  FOUND   |
           +----------+

Please have a closer look of the transients 2->2 and
4->2. They heavily depend on the 0xff bytes found in the
SOF marker. You might also want to have a look at the attached
test cases to see why the state machine is necessary.

Regards,

	Márton Németh


/*
  Test the function pac_find_sof() from file
  linux/drivers/media/video/gspca/pac_common.h

  Test based on Linux kernel 2.6.32-rc1
  Written by Márton Németh <nm127@xxxxxxxxxxx>, 4 Oct 2009
  Released under GPL
*/

#include <stdio.h>

struct sd {
	unsigned int sof_read;
};

struct gspca_dev {
    struct sd* sd;
};

#define PDEBUG(level, fmt, args...) \
	do {\
		printf("PDEBUG: " fmt "\n", ## args); \
	} while (0)

#include "pac_common.h"

int tc1() {
	static unsigned char test[] = { 0xff, 0xff, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 1: exact match\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == &test[5]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc2() {
	static unsigned char test[] = { 0x00, 0xff, 0xff, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 2: offset 1\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == &test[6]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc3() {
	static unsigned char test[] = { 0xff, 0xff, 0xff, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 3: offset 1, first byte may be misleading\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == &test[6]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc4() {
	static unsigned char test[] = { 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 4: offset 2, first two bytes may be misleading\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == &test[7]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc5() {
	static unsigned char test[] = { 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 5: offset 3, first three bytes may be misleading\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == &test[8]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc6() {
	static unsigned char test[] = { 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 6: offset 4, first four bytes may be misleading\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == &test[9]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc7() {
	static unsigned char test1[] = { 0xff, 0xff, 0x00, 0xff };
	static unsigned char test2[] = { 0x96 };
	unsigned char* p1;
	unsigned char* p2;
	struct sd sd;
	int result = 0;

	printf("Test case 7: pattern starts at end of packet and continues in the next one\n");
	sd.sof_read = 0;
	p1 = pac_find_sof((struct gspca_dev*)&sd, test1, sizeof(test1));
	p2 = pac_find_sof((struct gspca_dev*)&sd, test2, sizeof(test2));
	if (p1 == NULL && p2 == &test2[1]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc8() {
	static unsigned char test1[] = { 0xff, 0xff, 0xff, 0x00, 0xff };
	static unsigned char test2[] = { 0x96 };
	unsigned char* p1;
	unsigned char* p2;
	struct sd sd;
	int result = 0;

	printf("Test case 8: splited pattern, with misleading first byte\n");
	sd.sof_read = 0;
	p1 = pac_find_sof((struct gspca_dev*)&sd, test1, sizeof(test1));
	p2 = pac_find_sof((struct gspca_dev*)&sd, test2, sizeof(test2));
	if (p1 == NULL && p2 == &test2[1]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc9() {
	static unsigned char test1[] = { 0xff, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff };
	static unsigned char test2[] = { 0x96 };
	unsigned char* p1;
	unsigned char* p2;
	struct sd sd;
	int result = 0;

	printf("Test case 9: splited pattern, with misleading first three bytes\n");
	sd.sof_read = 0;
	p1 = pac_find_sof((struct gspca_dev*)&sd, test1, sizeof(test1));
	p2 = pac_find_sof((struct gspca_dev*)&sd, test2, sizeof(test2));
	if (p1 == NULL && p2 == &test2[1]) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc10() {
	static unsigned char test[] = { 0xff, 0xaa, 0xff, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 10: no match, extra byte at offset 1\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == NULL) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc11() {
	static unsigned char test[] = { 0xff, 0xff, 0xaa, 0x00, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 11: no match, extra byte at offset 2\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == NULL) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc12() {
	static unsigned char test[] = { 0xff, 0xff, 0x00, 0xaa, 0xff, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 12: no match, extra byte at offset 3\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == NULL) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}

int tc13() {
	static unsigned char test[] = { 0xff, 0xff, 0x00, 0xff, 0xaa, 0x96 };
	unsigned char* p;
	struct sd sd;
	int result = 0;

	printf("Test case 13: no match, extra byte at offset 4\n");
	sd.sof_read = 0;
	p = pac_find_sof((struct gspca_dev*)&sd, test, sizeof(test));
	if (p == NULL) {
		printf("PASSED\n");
	} else {
		printf("FAILED\n");
		result = 1;
	}
	printf("\n");

	return result;
}


int main() {
	int result = 0;

	result += tc1();
	result += tc2();
	result += tc3();
	result += tc4();
	result += tc5();
	result += tc6();
	result += tc7();
	result += tc8();
	result += tc9();
	result += tc10();
	result += tc11();
	result += tc12();
	result += tc13();

	return result;
}

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux