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