xref: /haiku/src/add-ons/media/media-add-ons/usb_webcam/CamBufferingDeframer.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright 2004-2008, François Revol, <revol@free.fr>.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 /*
7  * buffer based deframer
8  * buffers all packet until it finds a complete frame.
9  * simpler than StreamingDeframer, but doesn't work any better
10  * and hogs the cpu intermitently :^)
11  */
12 
13 #define CD_COL "31"
14 #include "CamBufferingDeframer.h"
15 #include "CamDevice.h"
16 #include "CamDebug.h"
17 #include <Autolock.h>
18 #define MAX_TAG_LEN CAMDEFRAMER_MAX_TAG_LEN
19 #define MAXFRAMEBUF CAMDEFRAMER_MAX_QUEUED_FRAMES
20 
21 #define IB fInputBuffs[fInputBuffIndex]
22 
23 
24 CamBufferingDeframer::CamBufferingDeframer(CamDevice *device)
25 	: CamDeframer(device),
26 	fInputBuffIndex(0)
27 {
28 }
29 
30 
31 CamBufferingDeframer::~CamBufferingDeframer()
32 {
33 }
34 
35 
36 ssize_t
37 CamBufferingDeframer::Write(const void *buffer, size_t size)
38 {
39 	uint8 *b;
40 	int l;
41 	int i, s, e;
42 	int which;
43 	fMinFrameSize = fDevice->MinRawFrameSize();
44 	fMaxFrameSize = fDevice->MaxRawFrameSize();
45 	IB.Write(buffer, size);
46 	b = (uint8 *)IB.Buffer();
47 	l = IB.BufferLength();
48 
49 	PRINT((CH "(%p, %" B_PRIuSIZE "), IB: %" B_PRIuSIZE CT, buffer, size,
50 		IB.BufferLength()));
51 
52 	if (l < (int)(fMinFrameSize + fSkipSOFTags + fSkipEOFTags))
53 		return size; // not enough data anyway
54 
55 	if (!fCurrentFrame) {
56 		BAutolock l(fLocker);
57 		if (fFrames.CountItems() < MAXFRAMEBUF)
58 			fCurrentFrame = AllocFrame();
59 		else {
60 			PRINT((CH "DROPPED %" B_PRIuSIZE " bytes! "
61 				"(too many queued frames)" CT, size));
62 			return size; // drop XXX
63 		}
64 	}
65 
66 	for (s = 0; (l - s > (int)fMinFrameSize) && ((i = FindSOF(b + s, l - fMinFrameSize - s, &which)) > -1); s++) {
67 		s += i;
68 		if ((int)(s + fSkipSOFTags + fMinFrameSize + fSkipEOFTags) > l)
69 			break;
70 		if (!fDevice->ValidateStartOfFrameTag(b + s, fSkipSOFTags))
71 			continue;
72 
73 		PRINT((CH ": SOF[%d] at offset %d" CT, which, s));
74 		PRINT((CH ": SOF: ... %02x %02x %02x %02x %02x %02x" CT, b[s+6], b[s+7], b[s+8], b[s+9], b[s+10], b[s+11]));
75 
76 		for (e = s + fSkipSOFTags + fMinFrameSize;
77 			 ((e <= (int)(s + fSkipSOFTags + fMaxFrameSize)) &&
78 			  (e < l) && ((i = 0*FindEOF(b + e, l - e, &which)) > -1));
79 			 e++) {
80 			e += i;
81 
82 			//PRINT((CH ": EOF[%d] at offset %d" CT, which, s));
83 			if (!fDevice->ValidateEndOfFrameTag(b + e, fSkipEOFTags, e - s - fSkipSOFTags))
84 				continue;
85 
86 
87 
88 		PRINT((CH ": SOF= ... %02x %02x %02x %02x %02x %02x" CT, b[s+6], b[s+7], b[s+8], b[s+9], b[s+10], b[s+11]));
89 
90 			// we have one!
91 			s += fSkipSOFTags;
92 
93 			// fill it
94 			fCurrentFrame->Write(b + s, e - s);
95 
96 			// queue it
97 			BAutolock f(fLocker);
98 			PRINT((CH ": Detaching a frame (%" B_PRIuSIZE " bytes, "
99 				"%d to %d / %d)" CT, (size_t)fCurrentFrame->Position(),
100 				s, e, l));
101 			fCurrentFrame->Seek(0LL, SEEK_SET);
102 			fFrames.AddItem(fCurrentFrame);
103 			release_sem(fFrameSem);
104 			// next Write() will allocate a new one
105 			fCurrentFrame = NULL;
106 			// discard the frame and everything before it.
107 			DiscardFromInput(e + fSkipEOFTags);
108 
109 			return size;
110 		}
111 	}
112 	return size;
113 }
114 
115 
116 size_t
117 CamBufferingDeframer::DiscardFromInput(size_t size)
118 {
119 	int next = (fInputBuffIndex+1)%2;
120 	PRINT((CH ": %" B_PRIuSIZE " bytes of %" B_PRIuSIZE " from buffs[%d] "
121 		"(%" B_PRIuSIZE " left)" CT,
122 		size, IB.BufferLength(), fInputBuffIndex, IB.BufferLength() - size));
123 	fInputBuffs[next].Seek(0LL, SEEK_SET);
124 	fInputBuffs[next].SetSize(0);
125 	uint8 *buff = (uint8 *)IB.Buffer();
126 	if (IB.BufferLength() > size) {
127 		buff += size;
128 		fInputBuffs[next].Write(buff, IB.BufferLength() - size);
129 	}
130 	IB.Seek(0LL, SEEK_SET);
131 	IB.SetSize(0);
132 	fInputBuffIndex = next;
133 	return size;
134 }
135