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