2 Copyright 2004-2005 Chris Tallon
4 This file is part of VOMP.
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.
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.
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.
21 #include "recplayer.h"
23 #define _XOPEN_SOURCE 600
26 RecPlayer::RecPlayer(cRecording* rec)
28 log = Log::getInstance();
33 for(int i = 1; i < 1000; i++) segments[i] = NULL;
35 // FIXME find out max file path / name lengths
36 #if VDRVERSNUM < 10703
37 indexFile = new cIndexFile(recording->FileName(), false);
39 indexFile = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
41 if (!indexFile) log->log("RecPlayer", Log::ERR, "Failed to create indexfile!");
46 void RecPlayer::scan()
48 if (file) fclose(file);
54 while(segments[i++]) delete segments[i];
57 #if VDRVERSNUM < 10703
58 for(i = 1; i < 255; i++)//maximum is 255 files instead of 1000, according to VDR HISTORY file...
60 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
62 for(i = 1; i < 65535; i++)
64 if (recording->IsPesRecording())
65 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
67 snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), i);
69 log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
70 file = fopen(fileName, "r");
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;
86 RecPlayer::~RecPlayer()
88 log->log("RecPlayer", Log::DEBUG, "destructor");
90 while(segments[i++]) delete segments[i];
91 if (file) fclose(file);
94 int RecPlayer::openFile(int index)
96 if (file) fclose(file);
99 #if VDRVERSNUM < 10703
100 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
102 if (recording->IsPesRecording())
103 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
105 snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), index);
107 log->log("RecPlayer", Log::DEBUG, "openFile called for index %i string:%s", index, fileName);
109 file = fopen(fileName, "r");
112 log->log("RecPlayer", Log::DEBUG, "file failed to open");
120 ULLONG RecPlayer::getLengthBytes()
125 ULONG RecPlayer::getLengthFrames()
130 unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsigned long amount)
132 if ((amount > totalLength) || (amount > 500000))
134 log->log("RecPlayer", Log::DEBUG, "Amount %lu requested and rejected", amount);
138 if (position >= totalLength)
140 log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
144 if ((position + amount) > totalLength)
146 log->log("RecPlayer", Log::DEBUG, "Client asked for some data past the end of recording, adjusting amount");
147 amount = totalLength - position;
150 // work out what block position is in
152 for(segmentNumber = 1; segmentNumber < 1000; segmentNumber++)
154 if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
155 // position is in this block
158 // we could be seeking around
159 if (segmentNumber != fileOpen)
161 if (!openFile(segmentNumber)) return 0;
164 ULLONG currentPosition = position;
165 ULONG yetToGet = amount;
167 ULONG getFromThisSegment = 0;
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;
179 // is the request completely in this block?
180 if ((currentPosition + yetToGet) <= segments[segmentNumber]->end)
181 getFromThisSegment = yetToGet;
183 getFromThisSegment = segments[segmentNumber]->end - currentPosition;
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.
189 // Tell linux not to bother keeping the data in the FS cache
190 posix_fadvise(file->_fileno, filePosition, getFromThisSegment, POSIX_FADV_DONTNEED);
192 got += getFromThisSegment;
193 currentPosition += getFromThisSegment;
194 yetToGet -= getFromThisSegment;
197 lastPosition = position;
201 ULLONG RecPlayer::getLastPosition()
206 cRecording* RecPlayer::getCurrentRecording()
211 ULLONG RecPlayer::positionFromFrameNumber(ULONG frameNumber)
213 if (!indexFile) return 0;
214 #if VDRVERSNUM < 10703
219 uint16_t retFileNumber;
226 if (!indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
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);
239 ULONG RecPlayer::frameNumberFromPosition(ULLONG position)
241 if (!indexFile) return 0;
243 if (position >= totalLength)
245 log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
250 for(segmentNumber = 1; segmentNumber < 255; segmentNumber++)
252 if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
253 // position is in this block
255 ULONG askposition = position - segments[segmentNumber]->start;
256 return indexFile->Get((int)segmentNumber, askposition);
261 bool RecPlayer::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
266 if (!indexFile) return false;
268 #if VDRVERSNUM < 10703
277 int indexReturnFrameNumber;
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);
282 if (indexReturnFrameNumber == -1) return false;
284 *rfilePosition = positionFromFrameNumber(indexReturnFrameNumber);
285 *rframeNumber = (ULONG)indexReturnFrameNumber;
286 *rframeLength = (ULONG)iframeLength;