xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
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) {
71 		off_t position = fCurrentFrame->Position();
72 		if (position + bufsize < 0
73 			|| (size_t)(position + bufsize) < fMinFrameSize) {
74 			// no residual data, and
75 			fCurrentFrame->Write(buf, bufsize);
76 			fInputBuff.Seek(0LL, SEEK_SET);
77 			fInputBuff.SetSize(0);
78 			return size;
79 		}
80 	}
81 
82 	// waiting for a frame...
83 	if (fState == ST_SYNC) {
84 		i = 0;
85 		while ((j = FindSOF(buf+i, bufsize-i, &which)) > -1) {
86 			i += j;
87 			if (fDevice->ValidateStartOfFrameTag(buf+i, fSkipSOFTags))
88 				break;
89 			i++;
90 		}
91 		// got one
92 		if (j >= 0) {
93 			PRINT((CH ": SOF[%d] at offset %d" CT, which, i));
94 			//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]));
95 			int start = i + fSkipSOFTags;
96 			buf += start;
97 			bufsize -= start;
98 			end = bufsize;
99 			fState = ST_FRAME;
100 		}
101 	}
102 
103 	// check for end of frame
104 	if (fState == ST_FRAME) {
105 #if 0
106 		int j, k;
107 		i = -1;
108 		k = 0;
109 		while ((j = FindEOF(buf + k, bufsize - k, &which)) > -1) {
110 			k += j;
111 			//PRINT((CH "| EOF[%d] at offset %d; pos %lld" CT, which, k, fCurrentFrame->Position()));
112 			if (fCurrentFrame->Position()+k >= fMinFrameSize) {
113 				i = k;
114 				break;
115 			}
116 			k++;
117 			if (k >= bufsize)
118 				break;
119 		}
120 #endif
121 #if 1
122 		i = 0;
123 		off_t currentFramePosition = fCurrentFrame->Position();
124 		if (currentFramePosition < 0
125 			|| (size_t)currentFramePosition < fMinFrameSize) {
126 			if (currentFramePosition + bufsize > 0
127 				&& (size_t)(currentFramePosition + bufsize) >= fMinFrameSize) {
128 				i = (fMinFrameSize - (size_t)fCurrentFrame->Position());
129 			} else
130 				i = bufsize;
131 		}
132 		PRINT((CH ": checking for EOF; bufsize=%d i=%d" CT, bufsize, i));
133 
134 		if (i + (int)fSkipEOFTags > bufsize) { // not enough room to check for EOF, leave it for next time
135 			end = i;
136 			i = -1; // don't detach yet
137 		} else {
138 			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]));
139 			while ((j = FindEOF(buf + i, bufsize - i, &which)) > -1) {
140 				i += j;
141 				PRINT((CH "| EOF[%d] at offset %d; pos %" B_PRIdOFF CT,
142 					which, i, fCurrentFrame->Position()));
143 				off_t position = fCurrentFrame->Position();
144 				if (position + i >= 0
145 					&& (size_t)(position + i) >= fMaxFrameSize) {
146 					// too big: discard
147 					//i = -1;
148 					discard = true;
149 					break;
150 				}
151 				if (fDevice->ValidateEndOfFrameTag(buf+i, fSkipEOFTags, fCurrentFrame->Position()+i))
152 					break;
153 				i++;
154 				if (i >= bufsize) {
155 					i = -1;
156 					break;
157 				}
158 			}
159 			if (j < 0)
160 				i = -1;
161 		}
162 #endif
163 		if (i >= 0) {
164 			PRINT((CH ": EOF[%d] at offset %d" CT, which, i));
165 			end = i;
166 			detach = true;
167 		}
168 		PRINT((CH ": writing %d bytes" CT, end));
169 		if (end <= bufsize)
170 			fCurrentFrame->Write(buf, end);
171 		off_t currentPosition = fCurrentFrame->Position();
172 		if (currentPosition > 0
173 			&& (size_t)currentPosition > fMaxFrameSize) {
174 			fCurrentFrame->SetSize(fMaxFrameSize);
175 			detach = true;
176 		}
177 		if (detach) {
178 			BAutolock f(fLocker);
179 			PRINT((CH ": Detaching a frame "
180 				"(%" B_PRIuSIZE " bytes, end = %d, )" CT,
181 				(size_t)fCurrentFrame->Position(), end));
182 			fCurrentFrame->Seek(0LL, SEEK_SET);
183 			if (discard) {
184 				delete fCurrentFrame;
185 			} else {
186 				fFrames.AddItem(fCurrentFrame);
187 				release_sem(fFrameSem);
188 			}
189 			fCurrentFrame = NULL;
190 			if (fFrames.CountItems() < MAXFRAMEBUF) {
191 				fCurrentFrame = AllocFrame();
192 			}
193 			fState = ST_SYNC;
194 		}
195 	}
196 
197 
198 
199 
200 	// put the remainder in input buff, discarding old data
201 #if 0
202 	fInputBuff.Seek(0LL, SEEK_SET);
203 	if (bufsize - end > 0)
204 		fInputBuff.Write(buf+end, bufsize - end);
205 #endif
206 	BMallocIO m;
207 	m.Write(buf+end, bufsize - end);
208 	fInputBuff.Seek(0LL, SEEK_SET);
209 	if (bufsize - end > 0)
210 		fInputBuff.Write(m.Buffer(), bufsize - end);
211 	fInputBuff.SetSize(bufsize - end);
212 	return size;
213 }
214