blob: 7000c1459bb0745eff49416107eff799c5b4dc4c [file] [log] [blame]
Constantin Kaplinskyfbfbb922004-11-14 18:28:51 +00001/* Copyright (C) 2004 TightVNC Team. All Rights Reserved.
2 *
3 * This is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This software is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
16 * USA.
17 */
18
19// -=- FbsInputStream class
20
21#include <windows.h>
22
23#include <rfb/Exception.h>
24
25#include <rfbplayer/FbsInputStream.h>
26
27FbsInputStream::FbsInputStream(char* FileName) {
28 bufferSize = 0;
29 ptr = end = start = NULL;
30
31 timeOffset = 0;
32 seekOffset = -1;
33 startTime = GetTickCount();
34
35 playbackSpeed = 1.0;
36 seekBackwards = false;
37 paused = false;
38
39 fbsFile = fopen(FileName, "rb");
40 if (fbsFile == NULL) {
41 char *msg = new char[12 + sizeof(FileName)];
42 strcpy(msg, "Can't open ");
43 strcat(msg, FileName);
44 throw rfb::Exception(msg,"RfbPlayer Error");
45 }
46
47 byte b[12];
48 readNByte(b, 12);
49
50 if (b[0] != 'F' || b[1] != 'B' || b[2] != 'S' || b[3] != ' ' ||
51 b[4] != '0' || b[5] != '0' || b[6] != '1' || b[7] != '.' ||
52 b[8] < '0' || b[8] > '9' || b[9] < '0' || b[9] > '9' ||
53 b[10] < '0' || b[10] > '9' || b[11] != '\n') {
54 throw rfb::Exception("Incorrect protocol version", "RfbPlayer Error");
55 }
56}
57
58FbsInputStream::~FbsInputStream() {
59 if (start != NULL)
60 delete [] start;
61 ptr = end = start = NULL;
62 fclose(fbsFile);
63}
64
65int FbsInputStream::pos() {
66 return ptr - start;
67}
68
69//
70// Close FbsInputStream and free data buffer
71//
72
73void FbsInputStream::close() {
74 fclose(fbsFile);
75
76 startTime = -1;
77 timeOffset = 0;
78 seekOffset = -1;
79 seekBackwards = false;
80 paused = false;
81 playbackSpeed = 1.0;
82
83 if (start != NULL)
84 delete [] start;
85 ptr = end = start = NULL;
86 bufferSize = 0;
87}
88
89//
90// Fill data buffer from the session file (InStream::overrun() override)
91//
92
93int FbsInputStream::overrun(int itemSize, int nItems, bool wait=true) {
94 // Just wait unless we are performing playback OR seeking.
95 waitWhilePaused();
96
97 // Perform backwardSeek (throws the special exception)
98 if (seekBackwards) {
99 throw rfb::Exception("[REWIND]", "RfbPlayer");
100 }
101
102 // Save a tail of data
103 U8 *tmp;
104 int n = end - ptr;
105 if (n) {
106 tmp = new U8[n];
107 memmove(tmp, ptr, n);
108 }
109
110 bufferSize = (int)readUnsigned32();
111 if (bufferSize >= 0) {
112 if (start != NULL)
113 delete [] start;
114 int realSize = (bufferSize + 3) & 0xFFFFFFFC; // padding to multiple of 32-bits
115 ptr = start = new byte[realSize + n];
116 end = ptr + bufferSize + n;
117 if (n) {
118 memmove(start, tmp, n);
119 delete [] tmp;
120 }
121 readNByte(start + n, realSize);
122 timeOffset = (long)(readUnsigned32() / playbackSpeed);
123
124 if (itemSize * nItems > bufferSize)
125 nItems = bufferSize / itemSize;
126 }
127
128 if (bufferSize < 0 || timeOffset < 0) {
129 if (start != NULL)
130 delete [] start;
131 ptr = end = start = NULL;
132 bufferSize = 0;
133 return 0;
134 }
135
136 if (seekOffset >= 0) {
137 if (timeOffset >= seekOffset) {
138 startTime = GetTickCount() - seekOffset;
139 seekOffset = -1;
140 } else {
141 return nItems;
142 }
143 }
144
145 while (true) {
146 long timeDiff = startTime + timeOffset - GetTickCount();
147 if (timeDiff <= 0) {
148 break;
149 }
150 Sleep(timeDiff);
151 waitWhilePaused();
152 }
153
154 return nItems;
155}
156
157int FbsInputStream::readUnsigned32() {
158 byte buf[4];
159 if (!readNByte(buf, 4))
160 return -1;
161
162 return ((long)(buf[0] & 0xFF) << 24 |
163 (buf[1] & 0xFF) << 16 |
164 (buf[2] & 0xFF) << 8 |
165 (buf[3] & 0xFF));
166}
167
168//
169// Read n-bytes from the session file
170//
171
172bool FbsInputStream::readNByte(byte b[], int n) {
173 int off = 0;
174
175 while (off != n) {
176 int count = fread(b, 1, n - off, fbsFile);
177 if (count < n) {
178 if (ferror(fbsFile))
179 throw rfb::Exception("Read error from session file", "RfbPlayer Error");
180 if (feof(fbsFile))
181 throw rfb::Exception("[End Of File]", "RfbPlayer Error");
182 }
183 off += count;
184 }
185 return true;
186}
187
188void FbsInputStream::waitWhilePaused() {
189 while (paused && !isSeeking()) {
190 // A small delay helps to decrease the cpu usage
191 Sleep(20);
192 }
193}
194
195//
196// Methods providing additional functionality.
197//
198
199long FbsInputStream::getTimeOffset() {
200 long off = max(seekOffset, timeOffset);
201 return (long)(off * playbackSpeed);
202}
203
204void FbsInputStream::setTimeOffset(long pos) {
205 seekOffset = (long)(pos / playbackSpeed);
206 if (seekOffset < timeOffset) {
207 seekBackwards = true;
208 }
209}
210
211void FbsInputStream::setSpeed(double newSpeed) {
212 long newOffset = (long)(timeOffset * playbackSpeed / newSpeed);
213 startTime += timeOffset - newOffset;
214 timeOffset = newOffset;
215 if (isSeeking()) {
216 seekOffset = (long)(seekOffset * playbackSpeed / newSpeed);
217 }
218 playbackSpeed = newSpeed;
219}
220
221double FbsInputStream::getSpeed() {
222 return playbackSpeed;
223}
224
225bool FbsInputStream::isSeeking() {
226 return (seekOffset >= 0);
227}
228
229long FbsInputStream::getSeekOffset() {
230 return (long)(seekOffset * playbackSpeed);
231}
232
233bool FbsInputStream::isPaused() {
234 return paused;
235}
236
237void FbsInputStream::pausePlayback() {
238 paused = true;
239}
240
241void FbsInputStream::resumePlayback() {
242 paused = false;
243 startTime = GetTickCount() - timeOffset;
244}