7#include "libmythbase/mythconfig.h"
27#if HAVE_POSIX_FADVISE < 1
45#define LOC QString("FileRingBuf(%1): ").arg(m_filename)
47static const QStringList
kSubExt {
".ass",
".srt",
".ssa",
".sub",
".txt"};
48static const QStringList
kSubExtNoCheck {
".ass",
".srt",
".ssa",
".sub",
".txt",
".gif",
".png"};
65 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open remote file (%1) for write").arg(
m_filename));
88 else if (Timeout >= 0ms)
117 QFileInfo fileInfo(Filename);
118 if (fileInfo.exists() && !fileInfo.isReadable())
120 LOG(VB_GENERAL, LOG_ERR, QString(
"FileRingBuf(%1): File exists but is not readable by MythTV!")
130 [Extension] (
const QString& ext) ->
bool
131 {return ext.contains(Extension);});
132 return (it !=
nullptr);
138 QString vidFileName =
FileInfo.fileName();
139 QString dirName =
FileInfo.absolutePath();
141 QString baseName = vidFileName;
142 int suffixPos = vidFileName.lastIndexOf(QChar(
'.'));
144 baseName = vidFileName.left(suffixPos);
150 const QString findBaseName = baseName.replace(
"[",
"?")
155 for (
const auto & ext :
kSubExt)
156 list += findBaseName + ext;
162 dir.setPath(dirName);
163 const QStringList candidates = dir.entryList(list);
164 for (
const auto & candidate : candidates)
166 QFileInfo
file(dirName +
"/" + candidate);
168 return file.absoluteFilePath();
176 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"OpenFile(%1, %2 ms)")
177 .arg(Filename).arg(Retry.count()));
197 bool islocal = (!
m_filename.startsWith(
"/dev")) &&
202 std::array<char,kReadTestSize> buf {};
208 uint openAttempts = 0;
209 while ((openTimer.
elapsed() < Retry) || (openAttempts == 0))
230 ssize_t ret =
read(
m_fd2, buf.data(), buf.size());
248 if (0 == lseek(
m_fd2, 0, SEEK_SET))
253 LOG(VB_FILE, LOG_DEBUG,
LOC +
254 QString(
"OpenFile(): fadvise sequential "
259 LOG(VB_FILE, LOG_DEBUG,
LOC +
260 QString(
"OpenFile(): fadvise willneed "
278 QString extension =
file.completeSuffix().toLower();
284 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"OpenFile(): Could not open."));
289 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"OpenFile(): File too small (%1B).")
295 LOG(VB_GENERAL, LOG_ERR,
LOC +
"OpenFile(): Improper permissions.");
299 LOG(VB_GENERAL, LOG_ERR,
LOC +
"OpenFile(): Cannot seek in file.");
304 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"OpenFile() made %1 attempts in %2 ms")
305 .arg(openAttempts).arg(openTimer.
elapsed().count()));
310 QString dirName =
".";
312 int dirPos =
m_filename.lastIndexOf(QChar(
'/'));
319 QStringList auxFiles;
321 int suffixPos = tmpSubName.lastIndexOf(QChar(
'.'));
324 QString baseName = tmpSubName.left(suffixPos);
325 int extnleng = tmpSubName.size() - baseName.size() - 1;
326 QString extension = tmpSubName.right(extnleng);
330 for (
const auto & ext :
kSubExt)
331 auxFiles += baseName + ext;
338 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"RingBuffer::RingBuffer(): Failed to open remote file (%1)")
367 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Tried to ReOpen a read only file.");
428 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Invalid file descriptor in 'safe_read()'");
439 uint toread = Size - tot;
446 int ret = fstat(
m_fd2, &sb);
447 if (ret == 0 && S_ISREG(sb.st_mode))
454 LOG(VB_FILE, LOG_DEBUG,
LOC +
"not reading, reached EOF");
458 toread =
static_cast<uint>(std::min(sb.st_size - (
m_internalReadPos + tot),
static_cast<long long>(toread)));
459 if (toread < (Size - tot))
462 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"About to reach EOF, reading %1 wanted %2")
463 .arg(toread).arg(Size-tot));
470 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"read(%1) -- begin").arg(toread));
471 ret =
static_cast<int>(
read(
m_fd2,
static_cast<char*
>(
Buffer) + tot, toread));
472 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"read(%1) -> %2 end").arg(toread).arg(ret));
479 LOG(VB_GENERAL, LOG_ERR,
LOC +
"File I/O problem in 'safe_read()'" +
ENO);
487 tot +=
static_cast<uint>(ret);
519 return static_cast<int>(tot);
532 int ret = Remote->
Read(
Buffer,
static_cast<int>(Size));
535 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read(RemoteFile* ...): read failed");
538 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read() failed to seek reset");
544 LOG(VB_FILE, LOG_INFO,
LOC +
"safe_read(RemoteFile* ...): at EOF");
561 long long result = -1;
572 result = fstat(
m_fd2, &sb);
573 if (result == 0 && S_ISREG(sb.st_mode))
600 (Whence == SEEK_CUR && Position == 0)))
608 long long newposition = (SEEK_SET==Whence) ? Position :
m_readPos + Position;
616 LOG(VB_FILE, LOG_INFO,
LOC +
617 QString(
"Seek(): rbrpos: %1 rbwpos: %2\n\t\t\treadpos: %3 internalreadpos: %4")
619 bool used_opt =
false;
626 internal_backbuf = std::min(internal_backbuf, free - min_safety);
628 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek(): internal_backbuf: %1 sba: %2")
629 .arg(internal_backbuf).arg(sba));
630 if (internal_backbuf >= sba)
635 LOG(VB_FILE, LOG_INFO,
LOC +
636 QString(
"Seek(): OPT1 rbrPos: %1 rbwPos: %2"
637 "\n\t\t\treadpos: %3 internalreadpos: %4")
646 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek(): OPT2 rbrPos: %1 sba: %2")
666 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Seek(): fadvise willneed failed: ") +
ENO);
669 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek to %1 from ignore pos %2 returned %3")
707 long long off_end = 0xDEADBEEF;
708 if (SEEK_END == Whence)
718 newposition = fi.size() - off_end;
730 off_end =
file.size() - newposition;
734 if (off_end != 0xDEADBEEF)
736 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek(): Offset from end: %1").arg(off_end));
739 if (off_end == 250000)
741 LOG(VB_FILE, LOG_INFO,
LOC +
742 QString(
"Seek(): offset from end: %1").arg(off_end) +
743 "\n\t\t\t -- ignoring read ahead thread until next seek.");
755 QString cmd = QString(
"Seek(%1, SEEK_SET) ign ")
760 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd +
" Failed" +
ENO);
769 QString cmd2 = QString(
"Seek(%1, SEEK_SET) int ")
771 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd2 +
" Failed" +
ENO);
775 QString cmd2 = QString(
"Seek(%1, %2) int ")
778 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd2 +
" succeeded");
811 ret = lseek(
m_fd2, Position, Whence);
824 QString cmd = QString(
"Seek(%1, %2)").arg(Position)
826 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd +
" Failed" +
ENO);
static void usleep(std::chrono::microseconds time)
bool IsRegisteredFileForWrite(const QString &file)
int SafeRead(void *Buffer, uint Size) override
long long SeekInternal(long long Position, int Whence) override
long long GetReadPosition(void) const override
bool OpenFile(const QString &Filename, std::chrono::milliseconds Retry=kDefaultOpenTimeout) override
~MythFileBuffer() override
bool IsOpen(void) const override
bool ReOpen(const QString &Filename="") override
MythFileBuffer(const QString &Filename, bool Write, bool UseReadAhead, std::chrono::milliseconds Timeout)
long long GetRealFileSizeInternal(void) const override
A QElapsedTimer based timer to replace use of QTime as a timer.
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
void start(void)
starts measuring elapsed time.
bool ReOpen(const QString &newFilename)
int Read(void *data, int size)
long long Seek(long long pos, int whence, long long curpos=-1)
long long GetRealFileSize(void)
GetRealFileSize: returns the current remote file's size.
QStringList GetAuxiliaryFiles(void) const
long long GetFileSize(void) const
GetFileSize: returns the remote file's size at the time it was first opened Will query the server in ...
This class supports the writing of recordings to disk.
bool Open(void)
Opens the file we will be writing to.
bool ReOpen(const QString &newFilename="")
Reopens the file we are writing to or opens a new file.
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static constexpr int8_t POSIX_FADV_SEQUENTIAL
static constexpr int8_t POSIX_FADV_WILLNEED
static int posix_fadvise(int, off_t, off_t, int)
static constexpr int8_t O_LARGEFILE
static bool CheckPermissions(const QString &Filename)
static bool IsSubtitlePossible(const QString &Extension)
static constexpr int8_t O_BINARY
static const QStringList kSubExt
static QString LocalSubtitleFilename(QFileInfo &FileInfo)
static const QStringList kSubExtNoCheck
static constexpr int8_t O_STREAMING
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
std::chrono::seconds secsInPast(const QDateTime &past)
def read(device=None, features=[])