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