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