xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/CamStreamingDeframer.cpp (revision e53032e55dd3ce646da788cd78ee86a293d491c2)
12c9bd703SFrançois Revol /*
22c9bd703SFrançois Revol  * stream based deframer
32c9bd703SFrançois Revol  * has a state machine and handles each packet separately.
42c9bd703SFrançois Revol  * much more complex than the buffering one, and I thought it didn't work,
52c9bd703SFrançois Revol  * but since I fixed the rest it seems to be working even better without
62c9bd703SFrançois Revol  * taking the cpu over like the other one.
72c9bd703SFrançois Revol  */
82c9bd703SFrançois Revol 
92c9bd703SFrançois Revol #define CD_COL "31"
102c9bd703SFrançois Revol #include "CamStreamingDeframer.h"
112c9bd703SFrançois Revol #include "CamDevice.h"
122c9bd703SFrançois Revol #include "CamDebug.h"
132c9bd703SFrançois Revol #include <Autolock.h>
142c9bd703SFrançois Revol #define MAX_TAG_LEN CAMDEFRAMER_MAX_TAG_LEN
152c9bd703SFrançois Revol #define MAXFRAMEBUF CAMDEFRAMER_MAX_QUEUED_FRAMES
162c9bd703SFrançois Revol 
172c9bd703SFrançois Revol CamStreamingDeframer::CamStreamingDeframer(CamDevice *device)
182c9bd703SFrançois Revol : CamDeframer(device)
192c9bd703SFrançois Revol {
202c9bd703SFrançois Revol }
212c9bd703SFrançois Revol 
222c9bd703SFrançois Revol CamStreamingDeframer::~CamStreamingDeframer()
232c9bd703SFrançois Revol {
242c9bd703SFrançois Revol }
252c9bd703SFrançois Revol 
262c9bd703SFrançois Revol ssize_t
272c9bd703SFrançois Revol CamStreamingDeframer::Write(const void *buffer, size_t size)
282c9bd703SFrançois Revol {
292c9bd703SFrançois Revol 	int i = -1;
302c9bd703SFrançois Revol 	int j;
312c9bd703SFrançois Revol 	int end = size;
322c9bd703SFrançois Revol 	int which;
332c9bd703SFrançois Revol 	const uint8 *buf = (const uint8 *)buffer;
342c9bd703SFrançois Revol 	int bufsize = size;
352c9bd703SFrançois Revol 	bool detach = false;
362c9bd703SFrançois Revol 	bool discard = false;
377f2c1e80SFrançois Revol 	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()));
382c9bd703SFrançois Revol 	if (!fCurrentFrame) {
392c9bd703SFrançois Revol 		BAutolock l(fLocker);
402c9bd703SFrançois Revol 		if (fFrames.CountItems() < MAXFRAMEBUF)
412c9bd703SFrançois Revol 			fCurrentFrame = AllocFrame();
422c9bd703SFrançois Revol 		else {
432c9bd703SFrançois Revol 			PRINT((CH "DROPPED %d bytes! (too many queued frames)" CT, size));
442c9bd703SFrançois Revol 			return size; // drop XXX
452c9bd703SFrançois Revol 		}
462c9bd703SFrançois Revol 	}
472c9bd703SFrançois Revol 
482c9bd703SFrançois Revol 	// update in case resolution changed
492c9bd703SFrançois Revol 	fMinFrameSize = fDevice->MinRawFrameSize();
502c9bd703SFrançois Revol 	fMaxFrameSize = fDevice->MaxRawFrameSize();
512c9bd703SFrançois Revol 
522c9bd703SFrançois Revol 	if (fInputBuff.Position()) {
532c9bd703SFrançois Revol 		// residual data ? append to it
542c9bd703SFrançois Revol 		fInputBuff.Write(buffer, size);
552c9bd703SFrançois Revol 		// and use it as input buf
562c9bd703SFrançois Revol 		buf = (uint8 *)fInputBuff.Buffer();
572c9bd703SFrançois Revol 		bufsize = fInputBuff.BufferLength();
582c9bd703SFrançois Revol 		end = bufsize;
592c9bd703SFrançois Revol 	}
602c9bd703SFrançois Revol 	// whole buffer belongs to a frame, simple
612c9bd703SFrançois Revol 	if ((fState == ST_FRAME) && (fCurrentFrame->Position() + bufsize < fMinFrameSize)) {
622c9bd703SFrançois Revol 		// no residual data, and
632c9bd703SFrançois Revol 		fCurrentFrame->Write(buf, bufsize);
642c9bd703SFrançois Revol 		fInputBuff.Seek(0LL, SEEK_SET);
652c9bd703SFrançois Revol 		fInputBuff.SetSize(0);
662c9bd703SFrançois Revol 		return size;
672c9bd703SFrançois Revol 	}
682c9bd703SFrançois Revol 
692c9bd703SFrançois Revol 	// waiting for a frame...
702c9bd703SFrançois Revol 	if (fState == ST_SYNC) {
712c9bd703SFrançois Revol 		i = 0;
722c9bd703SFrançois Revol 		while ((j = FindSOF(buf+i, bufsize-i, &which)) > -1) {
732c9bd703SFrançois Revol 			i += j;
742c9bd703SFrançois Revol 			if (fDevice->ValidateStartOfFrameTag(buf+i, fSkipSOFTags))
752c9bd703SFrançois Revol 				break;
762c9bd703SFrançois Revol 			i++;
772c9bd703SFrançois Revol 		}
782c9bd703SFrançois Revol 		// got one
792c9bd703SFrançois Revol 		if (j >= 0) {
802c9bd703SFrançois Revol 			PRINT((CH ": SOF[%d] at offset %d" CT, which, i));
812c9bd703SFrançois Revol 			//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]));
822c9bd703SFrançois Revol 			int start = i + fSkipSOFTags;
832c9bd703SFrançois Revol 			buf += start;
842c9bd703SFrançois Revol 			bufsize -= start;
852c9bd703SFrançois Revol 			end = bufsize;
862c9bd703SFrançois Revol 			fState = ST_FRAME;
872c9bd703SFrançois Revol 		}
882c9bd703SFrançois Revol 	}
892c9bd703SFrançois Revol 
902c9bd703SFrançois Revol 	// check for end of frame
912c9bd703SFrançois Revol 	if (fState == ST_FRAME) {
922c9bd703SFrançois Revol #if 0
932c9bd703SFrançois Revol 		int j, k;
942c9bd703SFrançois Revol 		i = -1;
952c9bd703SFrançois Revol 		k = 0;
962c9bd703SFrançois Revol 		while ((j = FindEOF(buf + k, bufsize - k, &which)) > -1) {
972c9bd703SFrançois Revol 			k += j;
982c9bd703SFrançois Revol 			//PRINT((CH "| EOF[%d] at offset %d; pos %Ld" CT, which, k, fCurrentFrame->Position()));
992c9bd703SFrançois Revol 			if (fCurrentFrame->Position()+k >= fMinFrameSize) {
1002c9bd703SFrançois Revol 				i = k;
1012c9bd703SFrançois Revol 				break;
1022c9bd703SFrançois Revol 			}
1032c9bd703SFrançois Revol 			k++;
1042c9bd703SFrançois Revol 			if (k >= bufsize)
1052c9bd703SFrançois Revol 				break;
1062c9bd703SFrançois Revol 		}
1072c9bd703SFrançois Revol #endif
1082c9bd703SFrançois Revol #if 1
1092c9bd703SFrançois Revol 		i = 0;
1102c9bd703SFrançois Revol 		if (fCurrentFrame->Position() < fMinFrameSize) {
1112c9bd703SFrançois Revol 			if (fCurrentFrame->Position() + bufsize >= fMinFrameSize)
1122c9bd703SFrançois Revol 				i = (fMinFrameSize - (size_t)fCurrentFrame->Position());
1132c9bd703SFrançois Revol 			else
1142c9bd703SFrançois Revol 				i = bufsize;
1152c9bd703SFrançois Revol 		}
1162c9bd703SFrançois Revol 		PRINT((CH ": checking for EOF; bufsize=%d i=%d" CT, bufsize, i));
1172c9bd703SFrançois Revol 
118*e53032e5SFrançois Revol 		if (i + (int)fSkipEOFTags > bufsize) { // not enough room to check for EOF, leave it for next time
1192c9bd703SFrançois Revol 			end = i;
1202c9bd703SFrançois Revol 			i = -1; // don't detach yet
1212c9bd703SFrançois Revol 		} else {
1222c9bd703SFrançois Revol 			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]));
1232c9bd703SFrançois Revol 			while ((j = FindEOF(buf + i, bufsize - i, &which)) > -1) {
1242c9bd703SFrançois Revol 				i += j;
1252c9bd703SFrançois Revol 				PRINT((CH "| EOF[%d] at offset %d; pos %Ld" CT, which, i, fCurrentFrame->Position()));
1262c9bd703SFrançois Revol 				if (fCurrentFrame->Position()+i >= fMaxFrameSize) {
1272c9bd703SFrançois Revol 					// too big: discard
1282c9bd703SFrançois Revol 					//i = -1;
1292c9bd703SFrançois Revol 					discard = true;
1302c9bd703SFrançois Revol 					break;
1312c9bd703SFrançois Revol 				}
1322c9bd703SFrançois Revol 				if (fDevice->ValidateEndOfFrameTag(buf+i, fSkipEOFTags, fCurrentFrame->Position()+i))
1332c9bd703SFrançois Revol 					break;
1342c9bd703SFrançois Revol 				i++;
1352c9bd703SFrançois Revol 				if (i >= bufsize) {
1362c9bd703SFrançois Revol 					i = -1;
1372c9bd703SFrançois Revol 					break;
1382c9bd703SFrançois Revol 				}
1392c9bd703SFrançois Revol 			}
1402c9bd703SFrançois Revol 			if (j < 0)
1412c9bd703SFrançois Revol 				i = -1;
1422c9bd703SFrançois Revol 		}
1432c9bd703SFrançois Revol #endif
1442c9bd703SFrançois Revol 		if (i >= 0) {
1452c9bd703SFrançois Revol 			PRINT((CH ": EOF[%d] at offset %d" CT, which, i));
1462c9bd703SFrançois Revol 			end = i;
1472c9bd703SFrançois Revol 			detach = true;
1482c9bd703SFrançois Revol 		}
1492c9bd703SFrançois Revol 		PRINT((CH ": writing %d bytes" CT, end));
1502c9bd703SFrançois Revol 		if (end <= bufsize)
1512c9bd703SFrançois Revol 			fCurrentFrame->Write(buf, end);
1522c9bd703SFrançois Revol 		if (fCurrentFrame->Position() > fMaxFrameSize) {
1532c9bd703SFrançois Revol 			fCurrentFrame->SetSize(fMaxFrameSize);
1542c9bd703SFrançois Revol 			detach = true;
1552c9bd703SFrançois Revol 		}
1562c9bd703SFrançois Revol 		if (detach) {
1572c9bd703SFrançois Revol 			BAutolock f(fLocker);
1582c9bd703SFrançois Revol 			PRINT((CH ": Detaching a frame (%d bytes, end = %d, )" CT, (size_t)fCurrentFrame->Position(), end));
1592c9bd703SFrançois Revol 			fCurrentFrame->Seek(0LL, SEEK_SET);
1602c9bd703SFrançois Revol 			if (discard) {
1612c9bd703SFrançois Revol 				delete fCurrentFrame;
1622c9bd703SFrançois Revol 			} else {
1632c9bd703SFrançois Revol 				fFrames.AddItem(fCurrentFrame);
1642c9bd703SFrançois Revol 				release_sem(fFrameSem);
1652c9bd703SFrançois Revol 			}
1662c9bd703SFrançois Revol 			fCurrentFrame = NULL;
1672c9bd703SFrançois Revol 			if (fFrames.CountItems() < MAXFRAMEBUF) {
1682c9bd703SFrançois Revol 				fCurrentFrame = AllocFrame();
1692c9bd703SFrançois Revol 			}
1702c9bd703SFrançois Revol 			fState = ST_SYNC;
1712c9bd703SFrançois Revol 		}
1722c9bd703SFrançois Revol 	}
1732c9bd703SFrançois Revol 
1742c9bd703SFrançois Revol 
1752c9bd703SFrançois Revol 
1762c9bd703SFrançois Revol 
1772c9bd703SFrançois Revol 	// put the remainder in input buff, discarding old data
1782c9bd703SFrançois Revol #if 0
1792c9bd703SFrançois Revol 	fInputBuff.Seek(0LL, SEEK_SET);
1802c9bd703SFrançois Revol 	if (bufsize - end > 0)
1812c9bd703SFrançois Revol 		fInputBuff.Write(buf+end, bufsize - end);
1822c9bd703SFrançois Revol #endif
1832c9bd703SFrançois Revol 	BMallocIO m;
1842c9bd703SFrançois Revol 	m.Write(buf+end, bufsize - end);
1852c9bd703SFrançois Revol 	fInputBuff.Seek(0LL, SEEK_SET);
1862c9bd703SFrançois Revol 	if (bufsize - end > 0)
1872c9bd703SFrançois Revol 		fInputBuff.Write(m.Buffer(), bufsize - end);
1882c9bd703SFrançois Revol 	fInputBuff.SetSize(bufsize - end);
1892c9bd703SFrançois Revol 	return size;
1902c9bd703SFrançois Revol }
1912c9bd703SFrançois Revol 
192