9#include "libmythbase/mythconfig.h"
29#if HAVE_POSIX_FADVISE < 1
47#define LOC QString("FileRingBuf(%1): ").arg(m_filename)
49static const QStringList
kSubExt {
".ass",
".srt",
".ssa",
".sub",
".txt"};
50static const QStringList
kSubExtNoCheck {
".ass",
".srt",
".ssa",
".sub",
".txt",
".gif",
".png"};
67 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open remote file (%1) for write").arg(
m_filename));
90 else if (Timeout >= 0ms)
119 QFileInfo fileInfo(Filename);
120 if (fileInfo.exists() && !fileInfo.isReadable())
122 LOG(VB_GENERAL, LOG_ERR, QString(
"FileRingBuf(%1): File exists but is not readable by MythTV!")
132 [Extension] (
const QString& ext) ->
bool
133 {return ext.contains(Extension);});
134 return (it !=
nullptr);
140 QString vidFileName =
FileInfo.fileName();
141 QString dirName =
FileInfo.absolutePath();
143 QString baseName = vidFileName;
144 int suffixPos = vidFileName.lastIndexOf(QChar(
'.'));
146 baseName = vidFileName.left(suffixPos);
152 const QString findBaseName = baseName.replace(
"[",
"?")
157 for (
const auto & ext :
kSubExt)
158 list += findBaseName + ext;
164 dir.setPath(dirName);
165 const QStringList candidates = dir.entryList(list);
166 for (
const auto & candidate : candidates)
168 QFileInfo
file(dirName +
"/" + candidate);
170 return file.absoluteFilePath();
178 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"OpenFile(%1, %2 ms)")
179 .arg(Filename).arg(Retry.count()));
199 bool islocal = (!
m_filename.startsWith(
"/dev")) &&
204 std::array<char,kReadTestSize> buf {};
210 uint openAttempts = 0;
211 while ((openTimer.
elapsed() < Retry) || (openAttempts == 0))
228 std::this_thread::sleep_for(10ms);
232 ssize_t ret =
read(
m_fd2, buf.data(), buf.size());
246 std::this_thread::sleep_for(10ms);
250 if (0 == lseek(
m_fd2, 0, SEEK_SET))
254 LOG(VB_FILE, LOG_DEBUG,
LOC +
255 QString(
"OpenFile(): fadvise sequential "
260 LOG(VB_FILE, LOG_DEBUG,
LOC +
261 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);
517 std::this_thread::sleep_for(60ms);
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")
665 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"Seek(): fadvise willneed failed: ") +
ENO);
667 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek to %1 from ignore pos %2 returned %3")
705 long long off_end = 0xDEADBEEF;
706 if (SEEK_END == Whence)
716 newposition = fi.size() - off_end;
728 off_end =
file.size() - newposition;
732 if (off_end != 0xDEADBEEF)
734 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek(): Offset from end: %1").arg(off_end));
737 if (off_end == 250000)
739 LOG(VB_FILE, LOG_INFO,
LOC +
740 QString(
"Seek(): offset from end: %1").arg(off_end) +
741 "\n\t\t\t -- ignoring read ahead thread until next seek.");
753 QString cmd = QString(
"Seek(%1, SEEK_SET) ign ")
758 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd +
" Failed" +
ENO);
767 QString cmd2 = QString(
"Seek(%1, SEEK_SET) int ")
769 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd2 +
" Failed" +
ENO);
773 QString cmd2 = QString(
"Seek(%1, %2) int ")
776 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd2 +
" succeeded");
809 ret = lseek(
m_fd2, Position, Whence);
822 QString cmd = QString(
"Seek(%1, %2)").arg(Position)
824 LOG(VB_GENERAL, LOG_ERR,
LOC + cmd +
" Failed" +
ENO);
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=[])