]> git.vomp.tv Git - vompserver.git/blob - recplayer.c
FSF address change
[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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "recplayer.h"
22
23 #define _XOPEN_SOURCE 600
24 #include <fcntl.h>
25
26 RecPlayer::RecPlayer(cRecording* rec)
27 {
28   log = Log::getInstance();
29   file = NULL;
30   fileOpen = 0;
31   lastPosition = 0;
32   recording = rec;
33   for(int i = 1; i < 1000; i++) segments[i] = NULL;
34
35   // FIXME find out max file path / name lengths
36
37   indexFile = new cIndexFile(recording->FileName(), false);
38   if (!indexFile) log->log("RecPlayer", Log::ERR, "Failed to create indexfile!");
39
40   scan();
41 }
42
43 void RecPlayer::scan()
44 {
45   if (file) fclose(file);
46   totalLength = 0;
47   fileOpen = 0;
48   totalFrames = 0;
49
50   int i = 1;
51   while(segments[i++]) delete segments[i];
52
53   char fileName[2048];
54   for(i = 1; i < 1000; i++)
55   {
56     snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
57     log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
58     file = fopen(fileName, "r");
59     if (!file) break;
60
61     segments[i] = new Segment();
62     segments[i]->start = totalLength;
63     fseek(file, 0, SEEK_END);
64     totalLength += ftell(file);
65     totalFrames = indexFile->Last();
66     log->log("RecPlayer", Log::DEBUG, "File %i found, totalLength now %llu, numFrames = %lu", i, totalLength, totalFrames);
67     segments[i]->end = totalLength;
68     fclose(file);
69   }
70
71   file = NULL;
72 }
73
74 RecPlayer::~RecPlayer()
75 {
76   log->log("RecPlayer", Log::DEBUG, "destructor");
77   int i = 1;
78   while(segments[i++]) delete segments[i];
79   if (file) fclose(file);
80 }
81
82 int RecPlayer::openFile(int index)
83 {
84   if (file) fclose(file);
85
86   char fileName[2048];
87   snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
88   log->log("RecPlayer", Log::DEBUG, "openFile called for index %i string:%s", index, fileName);
89
90   file = fopen(fileName, "r");
91   if (!file)
92   {
93     log->log("RecPlayer", Log::DEBUG, "file failed to open");
94     fileOpen = 0;
95     return 0;
96   }
97   fileOpen = index;
98   return 1;
99 }
100
101 ULLONG RecPlayer::getLengthBytes()
102 {
103   return totalLength;
104 }
105
106 ULONG RecPlayer::getLengthFrames()
107 {
108   return totalFrames;
109 }
110
111 unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsigned long amount)
112 {
113   if ((amount > totalLength) || (amount > 500000))
114   {
115     log->log("RecPlayer", Log::DEBUG, "Amount %lu requested and rejected", amount);
116     return 0;
117   }
118
119   if (position >= totalLength)
120   {
121     log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
122     return 0;
123   }
124
125   if ((position + amount) > totalLength)
126   {
127     log->log("RecPlayer", Log::DEBUG, "Client asked for some data past the end of recording, adjusting amount");
128     amount = totalLength - position;
129   }
130
131   // work out what block position is in
132   int segmentNumber;
133   for(segmentNumber = 1; segmentNumber < 1000; segmentNumber++)
134   {
135     if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
136     // position is in this block
137   }
138
139   // we could be seeking around
140   if (segmentNumber != fileOpen)
141   {
142     if (!openFile(segmentNumber)) return 0;
143   }
144
145   ULLONG currentPosition = position;
146   ULONG yetToGet = amount;
147   ULONG got = 0;
148   ULONG getFromThisSegment = 0;
149   ULONG filePosition;
150
151   while(got < amount)
152   {
153     if (got)
154     {
155       // if(got) then we have already got some and we are back around
156       // advance the file pointer to the next file
157       if (!openFile(++segmentNumber)) return 0;
158     }
159
160     // is the request completely in this block?
161     if ((currentPosition + yetToGet) <= segments[segmentNumber]->end)
162       getFromThisSegment = yetToGet;
163     else
164       getFromThisSegment = segments[segmentNumber]->end - currentPosition;
165
166     filePosition = currentPosition - segments[segmentNumber]->start;
167     fseek(file, filePosition, SEEK_SET);
168     if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem.
169  
170     // Tell linux not to bother keeping the data in the FS cache
171     posix_fadvise(file->_fileno, filePosition, getFromThisSegment, POSIX_FADV_DONTNEED);
172  
173     got += getFromThisSegment;
174     currentPosition += getFromThisSegment;
175     yetToGet -= getFromThisSegment;
176   }
177
178   lastPosition = position;
179   return got;
180 }
181
182 ULLONG RecPlayer::getLastPosition()
183 {
184   return lastPosition;
185 }
186
187 cRecording* RecPlayer::getCurrentRecording()
188 {
189   return recording;
190 }
191
192 ULLONG RecPlayer::positionFromFrameNumber(ULONG frameNumber)
193 {
194   if (!indexFile) return 0;
195
196   uchar retFileNumber;
197   int retFileOffset;
198   uchar retPicType;
199   int retLength;
200
201   if (!indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
202   {
203     return 0;
204   }
205
206 //  log->log("RecPlayer", Log::DEBUG, "FN: %u FO: %i", retFileNumber, retFileOffset);
207   if (!segments[retFileNumber]) return 0;
208   ULLONG position = segments[retFileNumber]->start + retFileOffset;
209 //  log->log("RecPlayer", Log::DEBUG, "Pos: %llu", position);
210
211   return position;
212 }
213
214 ULONG RecPlayer::frameNumberFromPosition(ULLONG position)
215 {
216   if (!indexFile) return 0;
217
218   if (position >= totalLength)
219   {
220     log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
221     return 0;
222   }
223
224   uchar segmentNumber;
225   for(segmentNumber = 1; segmentNumber < 255; segmentNumber++)
226   {
227     if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
228     // position is in this block
229   }
230   ULONG askposition = position - segments[segmentNumber]->start;
231   return indexFile->Get((int)segmentNumber, askposition);
232
233 }
234
235
236 bool RecPlayer::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
237 {
238   // 0 = backwards
239   // 1 = forwards
240
241   if (!indexFile) return false;
242
243   uchar waste1;
244   int waste2;
245
246   int iframeLength;
247   int indexReturnFrameNumber;
248
249   indexReturnFrameNumber = (ULONG)indexFile->GetNextIFrame(frameNumber, (direction==1 ? true : false), &waste1, &waste2, &iframeLength);
250   log->log("RecPlayer", Log::DEBUG, "GNIF input framenumber:%lu, direction=%lu, output:framenumber=%i, framelength=%i", frameNumber, direction, indexReturnFrameNumber, iframeLength);
251
252   if (indexReturnFrameNumber == -1) return false;
253
254   *rfilePosition = positionFromFrameNumber(indexReturnFrameNumber);
255   *rframeNumber = (ULONG)indexReturnFrameNumber;
256   *rframeLength = (ULONG)iframeLength;
257
258   return true;
259 }