]> git.vomp.tv Git - vompserver.git/blob - recplayer.c
Streaming update
[vompserver.git] / recplayer.c
1 /*
2     Copyright 2004-2005 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "recplayer.h"
22
23 RecPlayer::RecPlayer(cRecording* rec)
24 {
25   log = Log::getInstance();
26   file = NULL;
27   fileOpen = 0;
28   lastPosition = 0;
29   recording = rec;
30   for(int i = 1; i < 1000; i++) segments[i] = NULL;
31
32   // FIXME find out max file path / name lengths
33
34   indexFile = new cIndexFile(recording->FileName(), false);
35   if (!indexFile) log->log("RecPlayer", Log::ERR, "Failed to create indexfile!");
36
37   scan();
38 }
39
40 void RecPlayer::scan()
41 {
42   if (file) fclose(file);
43   totalLength = 0;
44   fileOpen = 0;
45   totalFrames = 0;
46
47   int i = 1;
48   while(segments[i++]) delete segments[i];
49
50   char fileName[2048];
51   for(i = 1; i < 1000; i++)
52   {
53     snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
54     log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
55     file = fopen(fileName, "r");
56     if (!file) break;
57
58     segments[i] = new Segment();
59     segments[i]->start = totalLength;
60     fseek(file, 0, SEEK_END);
61     totalLength += ftell(file);
62     totalFrames = indexFile->Last();
63     log->log("RecPlayer", Log::DEBUG, "File %i found, totalLength now %llu, numFrames = %lu", i, totalLength, totalFrames);
64     segments[i]->end = totalLength;
65     fclose(file);
66   }
67
68   file = NULL;
69 }
70
71 RecPlayer::~RecPlayer()
72 {
73   log->log("RecPlayer", Log::DEBUG, "destructor");
74   int i = 1;
75   while(segments[i++]) delete segments[i];
76   if (file) fclose(file);
77 }
78
79 int RecPlayer::openFile(int index)
80 {
81   if (file) fclose(file);
82
83   char fileName[2048];
84   snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
85   log->log("RecPlayer", Log::DEBUG, "openFile called for index %i string:%s", index, fileName);
86
87   file = fopen(fileName, "r");
88   if (!file)
89   {
90     log->log("RecPlayer", Log::DEBUG, "file failed to open");
91     fileOpen = 0;
92     return 0;
93   }
94   fileOpen = index;
95   return 1;
96 }
97
98 ULLONG RecPlayer::getLengthBytes()
99 {
100   return totalLength;
101 }
102
103 ULONG RecPlayer::getLengthFrames()
104 {
105   return totalFrames;
106 }
107
108 unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsigned long amount)
109 {
110   if ((amount > totalLength) || (amount > 500000))
111   {
112     log->log("RecPlayer", Log::DEBUG, "Amount %lu requested and rejected", amount);
113     return 0;
114   }
115
116   if (position >= totalLength)
117   {
118     log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
119     return 0;
120   }
121
122   if ((position + amount) > totalLength)
123   {
124     log->log("RecPlayer", Log::DEBUG, "Client asked for some data past the end of recording, adjusting amount");
125     amount = totalLength - position;
126   }
127
128   // work out what block position is in
129   int segmentNumber;
130   for(segmentNumber = 1; segmentNumber < 1000; segmentNumber++)
131   {
132     if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
133     // position is in this block
134   }
135
136   // we could be seeking around
137   if (segmentNumber != fileOpen)
138   {
139     if (!openFile(segmentNumber)) return 0;
140   }
141
142   ULLONG currentPosition = position;
143   ULONG yetToGet = amount;
144   ULONG got = 0;
145   ULONG getFromThisSegment = 0;
146   ULONG filePosition;
147
148   while(got < amount)
149   {
150     if (got)
151     {
152       // if(got) then we have already got some and we are back around
153       // advance the file pointer to the next file
154       if (!openFile(++segmentNumber)) return 0;
155     }
156
157     // is the request completely in this block?
158     if ((currentPosition + yetToGet) <= segments[segmentNumber]->end)
159       getFromThisSegment = yetToGet;
160     else
161       getFromThisSegment = segments[segmentNumber]->end - currentPosition;
162
163     filePosition = currentPosition - segments[segmentNumber]->start;
164     fseek(file, filePosition, SEEK_SET);
165     if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem.
166
167     got += getFromThisSegment;
168     currentPosition += getFromThisSegment;
169     yetToGet -= getFromThisSegment;
170   }
171
172   lastPosition = position;
173   return got;
174 }
175
176 ULLONG RecPlayer::getLastPosition()
177 {
178   return lastPosition;
179 }
180
181 cRecording* RecPlayer::getCurrentRecording()
182 {
183   return recording;
184 }
185
186 ULLONG RecPlayer::positionFromFrameNumber(ULONG frameNumber)
187 {
188   if (!indexFile) return 0;
189
190   uchar retFileNumber;
191   int retFileOffset;
192   uchar retPicType;
193   int retLength;
194
195   if (!indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
196   {
197     return 0;
198   }
199
200 //  log->log("RecPlayer", Log::DEBUG, "FN: %u FO: %i", retFileNumber, retFileOffset);
201   if (!segments[retFileNumber]) return 0;
202   ULLONG position = segments[retFileNumber]->start + retFileOffset;
203 //  log->log("RecPlayer", Log::DEBUG, "Pos: %llu", position);
204
205   return position;
206 }
207
208 ULONG RecPlayer::frameNumberFromPosition(ULLONG position)
209 {
210   if (!indexFile) return 0;
211
212   if (position >= totalLength)
213   {
214     log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
215     return 0;
216   }
217
218   uchar segmentNumber;
219   for(segmentNumber = 1; segmentNumber < 255; segmentNumber++)
220   {
221     if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
222     // position is in this block
223   }
224   ULONG askposition = position - segments[segmentNumber]->start;
225   return indexFile->Get((int)segmentNumber, askposition);
226
227 }
228
229
230 bool RecPlayer::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
231 {
232   // 0 = backwards
233   // 1 = forwards
234
235   if (!indexFile) return false;
236
237   uchar waste1;
238   int waste2;
239
240   int iframeLength;
241   int indexReturnFrameNumber;
242
243   indexReturnFrameNumber = (ULONG)indexFile->GetNextIFrame(frameNumber, (direction==1 ? true : false), &waste1, &waste2, &iframeLength);
244   log->log("RecPlayer", Log::DEBUG, "GNIF input framenumber:%lu, direction=%lu, output:framenumber=%i, framelength=%i", frameNumber, direction, indexReturnFrameNumber, iframeLength);
245
246   if (indexReturnFrameNumber == -1) return false;
247
248   *rfilePosition = positionFromFrameNumber(indexReturnFrameNumber);
249   *rframeNumber = (ULONG)indexReturnFrameNumber;
250   *rframeLength = (ULONG)iframeLength;
251
252   return true;
253 }