xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.cpp (revision 2c9bd70310636a2ce913fba5ef02a51008c06ef5)
1*2c9bd703SFrançois Revol /*
2*2c9bd703SFrançois Revol  * stream based deframer
3*2c9bd703SFrançois Revol  * has a state machine and handles each packet separately.
4*2c9bd703SFrançois Revol  * much more complex than the buffering one, and I thought it didn't work,
5*2c9bd703SFrançois Revol  * but since I fixed the rest it seems to be working even better without
6*2c9bd703SFrançois Revol  * taking the cpu over like the other one.
7*2c9bd703SFrançois Revol  */
8*2c9bd703SFrançois Revol 
9*2c9bd703SFrançois Revol #define CD_COL "31"
10*2c9bd703SFrançois Revol #include "CamStreamingDeframer.h"
11*2c9bd703SFrançois Revol #include "CamDevice.h"
12*2c9bd703SFrançois Revol #include "CamDebug.h"
13*2c9bd703SFrançois Revol #include <Autolock.h>
14*2c9bd703SFrançois Revol #define MAX_TAG_LEN CAMDEFRAMER_MAX_TAG_LEN
15*2c9bd703SFrançois Revol #define MAXFRAMEBUF CAMDEFRAMER_MAX_QUEUED_FRAMES
16*2c9bd703SFrançois Revol 
17*2c9bd703SFrançois Revol CamStreamingDeframer::CamStreamingDeframer(CamDevice *device)
18*2c9bd703SFrançois Revol : CamDeframer(device)
19*2c9bd703SFrançois Revol {
20*2c9bd703SFrançois Revol }
21*2c9bd703SFrançois Revol 
22*2c9bd703SFrançois Revol CamStreamingDeframer::~CamStreamingDeframer()
23*2c9bd703SFrançois Revol {
24*2c9bd703SFrançois Revol }
25*2c9bd703SFrançois Revol 
26*2c9bd703SFrançois Revol ssize_t
27*2c9bd703SFrançois Revol CamStreamingDeframer::Write(const void *buffer, size_t size)
28*2c9bd703SFrançois Revol {
29*2c9bd703SFrançois Revol 	int i = -1;
30*2c9bd703SFrançois Revol 	int j;
31*2c9bd703SFrançois Revol 	int end = size;
32*2c9bd703SFrançois Revol 	int which;
33*2c9bd703SFrançois Revol 	const uint8 *buf = (const uint8 *)buffer;
34*2c9bd703SFrançois Revol 	int bufsize = size;
35*2c9bd703SFrançois Revol 	bool detach = false;
36*2c9bd703SFrançois Revol 	bool discard = false;
37*2c9bd703SFrançois Revol 	PRINT((CH "(%p, %d); state=%s framesz=%u queued=%u" CT, buffer, size, (fState==ST_SYNC)?"sync":"frame", (size_t)fCurrentFrame->Position(), (size_t)fInputBuff.Position()));
38*2c9bd703SFrançois Revol 	if (!fCurrentFrame) {
39*2c9bd703SFrançois Revol 		BAutolock l(fLocker);
40*2c9bd703SFrançois Revol 		if (fFrames.CountItems() < MAXFRAMEBUF)
41*2c9bd703SFrançois Revol 			fCurrentFrame = AllocFrame();
42*2c9bd703SFrançois Revol 		else {
43*2c9bd703SFrançois Revol 			PRINT((CH "DROPPED %d bytes! (too many queued frames)" CT, size));
44*2c9bd703SFrançois Revol 			return size; // drop XXX
45*2c9bd703SFrançois Revol 		}
46*2c9bd703SFrançois Revol 	}
47*2c9bd703SFrançois Revol 
48*2c9bd703SFrançois Revol 	// update in case resolution changed
49*2c9bd703SFrançois Revol 	fMinFrameSize = fDevice->MinRawFrameSize();
50*2c9bd703SFrançois Revol 	fMaxFrameSize = fDevice->MaxRawFrameSize();
51*2c9bd703SFrançois Revol 
52*2c9bd703SFrançois Revol 	if (fInputBuff.Position()) {
53*2c9bd703SFrançois Revol 		// residual data ? append to it
54*2c9bd703SFrançois Revol 		fInputBuff.Write(buffer, size);
55*2c9bd703SFrançois Revol 		// and use it as input buf
56*2c9bd703SFrançois Revol 		buf = (uint8 *)fInputBuff.Buffer();
57*2c9bd703SFrançois Revol 		bufsize = fInputBuff.BufferLength();
58*2c9bd703SFrançois Revol 		end = bufsize;
59*2c9bd703SFrançois Revol 	}
60*2c9bd703SFrançois Revol 	// whole buffer belongs to a frame, simple
61*2c9bd703SFrançois Revol 	if ((fState == ST_FRAME) && (fCurrentFrame->Position() + bufsize < fMinFrameSize)) {
62*2c9bd703SFrançois Revol 		// no residual data, and
63*2c9bd703SFrançois Revol 		fCurrentFrame->Write(buf, bufsize);
64*2c9bd703SFrançois Revol 		fInputBuff.Seek(0LL, SEEK_SET);
65*2c9bd703SFrançois Revol 		fInputBuff.SetSize(0);
66*2c9bd703SFrançois Revol 		return size;
67*2c9bd703SFrançois Revol 	}
68*2c9bd703SFrançois Revol 
69*2c9bd703SFrançois Revol 	// waiting for a frame...
70*2c9bd703SFrançois Revol 	if (fState == ST_SYNC) {
71*2c9bd703SFrançois Revol 		i = 0;
72*2c9bd703SFrançois Revol 		while ((j = FindSOF(buf+i, bufsize-i, &which)) > -1) {
73*2c9bd703SFrançois Revol 			i += j;
74*2c9bd703SFrançois Revol 			if (fDevice->ValidateStartOfFrameTag(buf+i, fSkipSOFTags))
75*2c9bd703SFrançois Revol 				break;
76*2c9bd703SFrançois Revol 			i++;
77*2c9bd703SFrançois Revol 		}
78*2c9bd703SFrançois Revol 		// got one
79*2c9bd703SFrançois Revol 		if (j >= 0) {
80*2c9bd703SFrançois Revol 			PRINT((CH ": SOF[%d] at offset %d" CT, which, i));
81*2c9bd703SFrançois Revol 			//PRINT((CH ": SOF: ... %02x %02x %02x %02x %02x %02x" CT, buf[i+6], buf[i+7], buf[i+8], buf[i+9], buf[i+10], buf[i+11]));
82*2c9bd703SFrançois Revol 			int start = i + fSkipSOFTags;
83*2c9bd703SFrançois Revol 			buf += start;
84*2c9bd703SFrançois Revol 			bufsize -= start;
85*2c9bd703SFrançois Revol 			end = bufsize;
86*2c9bd703SFrançois Revol 			fState = ST_FRAME;
87*2c9bd703SFrançois Revol 		}
88*2c9bd703SFrançois Revol 	}
89*2c9bd703SFrançois Revol 
90*2c9bd703SFrançois Revol 	// check for end of frame
91*2c9bd703SFrançois Revol 	if (fState == ST_FRAME) {
92*2c9bd703SFrançois Revol #if 0
93*2c9bd703SFrançois Revol 		int j, k;
94*2c9bd703SFrançois Revol 		i = -1;
95*2c9bd703SFrançois Revol 		k = 0;
96*2c9bd703SFrançois Revol 		while ((j = FindEOF(buf + k, bufsize - k, &which)) > -1) {
97*2c9bd703SFrançois Revol 			k += j;
98*2c9bd703SFrançois Revol 			//PRINT((CH "| EOF[%d] at offset %d; pos %Ld" CT, which, k, fCurrentFrame->Position()));
99*2c9bd703SFrançois Revol 			if (fCurrentFrame->Position()+k >= fMinFrameSize) {
100*2c9bd703SFrançois Revol 				i = k;
101*2c9bd703SFrançois Revol 				break;
102*2c9bd703SFrançois Revol 			}
103*2c9bd703SFrançois Revol 			k++;
104*2c9bd703SFrançois Revol 			if (k >= bufsize)
105*2c9bd703SFrançois Revol 				break;
106*2c9bd703SFrançois Revol 		}
107*2c9bd703SFrançois Revol #endif
108*2c9bd703SFrançois Revol #if 1
109*2c9bd703SFrançois Revol 		i = 0;
110*2c9bd703SFrançois Revol 		if (fCurrentFrame->Position() < fMinFrameSize) {
111*2c9bd703SFrançois Revol 			if (fCurrentFrame->Position() + bufsize >= fMinFrameSize)
112*2c9bd703SFrançois Revol 				i = (fMinFrameSize - (size_t)fCurrentFrame->Position());
113*2c9bd703SFrançois Revol 			else
114*2c9bd703SFrançois Revol 				i = bufsize;
115*2c9bd703SFrançois Revol 		}
116*2c9bd703SFrançois Revol 		PRINT((CH ": checking for EOF; bufsize=%d i=%d" CT, bufsize, i));
117*2c9bd703SFrançois Revol 
118*2c9bd703SFrançois Revol 		if (i + fSkipEOFTags > bufsize) { // not enough room to check for EOF, leave it for next time
119*2c9bd703SFrançois Revol 			end = i;
120*2c9bd703SFrançois Revol 			i = -1; // don't detach yet
121*2c9bd703SFrançois Revol 		} else {
122*2c9bd703SFrançois Revol 			PRINT((CH ": EOF? %02x [%02x %02x %02x %02x] %02x" CT, buf[i-1], buf[i], buf[i+1], buf[i+2], buf[i+3], buf[i+4]));
123*2c9bd703SFrançois Revol 			while ((j = FindEOF(buf + i, bufsize - i, &which)) > -1) {
124*2c9bd703SFrançois Revol 				i += j;
125*2c9bd703SFrançois Revol 				PRINT((CH "| EOF[%d] at offset %d; pos %Ld" CT, which, i, fCurrentFrame->Position()));
126*2c9bd703SFrançois Revol 				if (fCurrentFrame->Position()+i >= fMaxFrameSize) {
127*2c9bd703SFrançois Revol 					// too big: discard
128*2c9bd703SFrançois Revol 					//i = -1;
129*2c9bd703SFrançois Revol 					discard = true;
130*2c9bd703SFrançois Revol 					break;
131*2c9bd703SFrançois Revol 				}
132*2c9bd703SFrançois Revol 				if (fDevice->ValidateEndOfFrameTag(buf+i, fSkipEOFTags, fCurrentFrame->Position()+i))
133*2c9bd703SFrançois Revol 					break;
134*2c9bd703SFrançois Revol 				i++;
135*2c9bd703SFrançois Revol 				if (i >= bufsize) {
136*2c9bd703SFrançois Revol 					i = -1;
137*2c9bd703SFrançois Revol 					break;
138*2c9bd703SFrançois Revol 				}
139*2c9bd703SFrançois Revol 			}
140*2c9bd703SFrançois Revol 			if (j < 0)
141*2c9bd703SFrançois Revol 				i = -1;
142*2c9bd703SFrançois Revol 		}
143*2c9bd703SFrançois Revol #endif
144*2c9bd703SFrançois Revol 		if (i >= 0) {
145*2c9bd703SFrançois Revol 			PRINT((CH ": EOF[%d] at offset %d" CT, which, i));
146*2c9bd703SFrançois Revol 			end = i;
147*2c9bd703SFrançois Revol 			detach = true;
148*2c9bd703SFrançois Revol 		}
149*2c9bd703SFrançois Revol 		PRINT((CH ": writing %d bytes" CT, end));
150*2c9bd703SFrançois Revol 		if (end <= bufsize)
151*2c9bd703SFrançois Revol 			fCurrentFrame->Write(buf, end);
152*2c9bd703SFrançois Revol 		if (fCurrentFrame->Position() > fMaxFrameSize) {
153*2c9bd703SFrançois Revol 			fCurrentFrame->SetSize(fMaxFrameSize);
154*2c9bd703SFrançois Revol 			detach = true;
155*2c9bd703SFrançois Revol 		}
156*2c9bd703SFrançois Revol 		if (detach) {
157*2c9bd703SFrançois Revol 			BAutolock f(fLocker);
158*2c9bd703SFrançois Revol 			PRINT((CH ": Detaching a frame (%d bytes, end = %d, )" CT, (size_t)fCurrentFrame->Position(), end));
159*2c9bd703SFrançois Revol 			fCurrentFrame->Seek(0LL, SEEK_SET);
160*2c9bd703SFrançois Revol 			if (discard) {
161*2c9bd703SFrançois Revol 				delete fCurrentFrame;
162*2c9bd703SFrançois Revol 			} else {
163*2c9bd703SFrançois Revol 				fFrames.AddItem(fCurrentFrame);
164*2c9bd703SFrançois Revol 				release_sem(fFrameSem);
165*2c9bd703SFrançois Revol 			}
166*2c9bd703SFrançois Revol 			fCurrentFrame = NULL;
167*2c9bd703SFrançois Revol 			if (fFrames.CountItems() < MAXFRAMEBUF) {
168*2c9bd703SFrançois Revol 				fCurrentFrame = AllocFrame();
169*2c9bd703SFrançois Revol 			}
170*2c9bd703SFrançois Revol 			fState = ST_SYNC;
171*2c9bd703SFrançois Revol 		}
172*2c9bd703SFrançois Revol 	}
173*2c9bd703SFrançois Revol 
174*2c9bd703SFrançois Revol 
175*2c9bd703SFrançois Revol 
176*2c9bd703SFrançois Revol 
177*2c9bd703SFrançois Revol 	// put the remainder in input buff, discarding old data
178*2c9bd703SFrançois Revol #if 0
179*2c9bd703SFrançois Revol 	fInputBuff.Seek(0LL, SEEK_SET);
180*2c9bd703SFrançois Revol 	if (bufsize - end > 0)
181*2c9bd703SFrançois Revol 		fInputBuff.Write(buf+end, bufsize - end);
182*2c9bd703SFrançois Revol #endif
183*2c9bd703SFrançois Revol 	BMallocIO m;
184*2c9bd703SFrançois Revol 	m.Write(buf+end, bufsize - end);
185*2c9bd703SFrançois Revol 	fInputBuff.Seek(0LL, SEEK_SET);
186*2c9bd703SFrançois Revol 	if (bufsize - end > 0)
187*2c9bd703SFrançois Revol 		fInputBuff.Write(m.Buffer(), bufsize - end);
188*2c9bd703SFrançois Revol 	fInputBuff.SetSize(bufsize - end);
189*2c9bd703SFrançois Revol 	return size;
190*2c9bd703SFrançois Revol }
191*2c9bd703SFrançois Revol 
192