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"
24 #define _XOPEN_SOURCE 600
29 RecPlayer::RecPlayer(cRecording* rec)
31 log = Log::getInstance();
36 for(int i = 1; i < 1000; i++) segments[i] = NULL;
38 // FIXME find out max file path / name lengths
39 #if VDRVERSNUM < 10703
40 indexFile = new cIndexFile(recording->FileName(), false);
42 indexFile = new cIndexFile(recording->FileName(), false, recording->IsPesRecording());
44 if (!indexFile) log->log("RecPlayer", Log::ERR, "Failed to create indexfile!");
49 void RecPlayer::scan()
51 if (file) fclose(file);
57 while(segments[i++]) delete segments[i];
60 #if VDRVERSNUM < 10703
61 for(i = 1; i < 255; i++)//maximum is 255 files instead of 1000, according to VDR HISTORY file...
63 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
65 for(i = 1; i < 65535; i++)
67 if (recording->IsPesRecording())
68 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), i);
70 snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), i);
72 log->log("RecPlayer", Log::DEBUG, "FILENAME: %s", fileName);
73 file = fopen(fileName, "r");
76 segments[i] = new Segment();
77 segments[i]->start = totalLength;
78 fseek(file, 0, SEEK_END);
79 totalLength += ftello(file);
80 totalFrames = indexFile->Last();
81 log->log("RecPlayer", Log::DEBUG, "File %i found, totalLength now %llu, numFrames = %lu", i, totalLength, totalFrames);
82 segments[i]->end = totalLength;
89 RecPlayer::~RecPlayer()
91 log->log("RecPlayer", Log::DEBUG, "destructor");
93 while(segments[i++]) delete segments[i];
94 if (file) fclose(file);
97 int RecPlayer::openFile(int index)
99 if (file) fclose(file);
102 #if VDRVERSNUM < 10703
103 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
105 if (recording->IsPesRecording())
106 snprintf(fileName, 2047, "%s/%03i.vdr", recording->FileName(), index);
108 snprintf(fileName, 2047, "%s/%05i.ts", recording->FileName(), index);
110 log->log("RecPlayer", Log::DEBUG, "openFile called for index %i string:%s", index, fileName);
112 file = fopen(fileName, "r");
115 log->log("RecPlayer", Log::DEBUG, "file failed to open");
123 ULLONG RecPlayer::getLengthBytes()
128 ULONG RecPlayer::getLengthFrames()
133 unsigned long RecPlayer::getBlock(unsigned char* buffer, ULLONG position, unsigned long amount)
135 if ((amount > totalLength) || (amount > 1000000))
137 log->log("RecPlayer", Log::DEBUG, "Amount %lu requested and rejected", amount);
141 if (position >= totalLength)
143 log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
147 if ((position + amount) > totalLength)
149 log->log("RecPlayer", Log::DEBUG, "Client asked for some data past the end of recording, adjusting amount");
150 amount = totalLength - position;
153 // work out what block position is in
155 for(segmentNumber = 1; segmentNumber < 1000; segmentNumber++)
157 if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
158 // position is in this block
161 // we could be seeking around
162 if (segmentNumber != fileOpen)
164 if (!openFile(segmentNumber)) return 0;
167 ULLONG currentPosition = position;
168 ULONG yetToGet = amount;
170 ULONG getFromThisSegment = 0;
177 // if(got) then we have already got some and we are back around
178 // advance the file pointer to the next file
179 if (!openFile(++segmentNumber)) return 0;
182 // is the request completely in this block?
183 if ((currentPosition + yetToGet) <= segments[segmentNumber]->end)
184 getFromThisSegment = yetToGet;
186 getFromThisSegment = segments[segmentNumber]->end - currentPosition;
188 filePosition = currentPosition - segments[segmentNumber]->start;
189 fseeko(file, filePosition, SEEK_SET);
190 if (fread(&buffer[got], getFromThisSegment, 1, file) != 1) return 0; // umm, big problem.
192 // Tell linux not to bother keeping the data in the FS cache
193 posix_fadvise(file->_fileno, filePosition, getFromThisSegment, POSIX_FADV_DONTNEED);
195 got += getFromThisSegment;
196 currentPosition += getFromThisSegment;
197 yetToGet -= getFromThisSegment;
200 lastPosition = position;
204 ULLONG RecPlayer::getLastPosition()
209 cRecording* RecPlayer::getCurrentRecording()
214 ULLONG RecPlayer::positionFromFrameNumber(ULONG frameNumber)
216 if (!indexFile) return 0;
217 #if VDRVERSNUM < 10703
222 uint16_t retFileNumber;
229 if (!indexFile->Get((int)frameNumber, &retFileNumber, &retFileOffset, &retPicType, &retLength))
234 // log->log("RecPlayer", Log::DEBUG, "FN: %u FO: %i", retFileNumber, retFileOffset);
235 if (!segments[retFileNumber]) return 0;
236 ULLONG position = segments[retFileNumber]->start + retFileOffset;
237 // log->log("RecPlayer", Log::DEBUG, "Pos: %llu", position);
242 ULONG RecPlayer::frameNumberFromPosition(ULLONG position)
244 if (!indexFile) return 0;
246 if (position >= totalLength)
248 log->log("RecPlayer", Log::DEBUG, "Client asked for data starting past end of recording!");
253 for(segmentNumber = 1; segmentNumber < 255; segmentNumber++)
255 if ((position >= segments[segmentNumber]->start) && (position < segments[segmentNumber]->end)) break;
256 // position is in this block
258 ULONG askposition = position - segments[segmentNumber]->start;
259 return indexFile->Get((int)segmentNumber, askposition);
264 bool RecPlayer::getNextIFrame(ULONG frameNumber, ULONG direction, ULLONG* rfilePosition, ULONG* rframeNumber, ULONG* rframeLength)
269 if (!indexFile) return false;
271 #if VDRVERSNUM < 10703
280 int indexReturnFrameNumber;
282 indexReturnFrameNumber = (ULONG)indexFile->GetNextIFrame(frameNumber, (direction==1 ? true : false), &waste1, &waste2, &iframeLength);
283 log->log("RecPlayer", Log::DEBUG, "GNIF input framenumber:%lu, direction=%lu, output:framenumber=%i, framelength=%i", frameNumber, direction, indexReturnFrameNumber, iframeLength);
285 if (indexReturnFrameNumber == -1) return false;
287 *rfilePosition = positionFromFrameNumber(indexReturnFrameNumber);
288 *rframeNumber = (ULONG)indexReturnFrameNumber;
289 *rframeLength = (ULONG)iframeLength;