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