10#include "libmythbase/mythconfig.h"
30#if HAVE_POSIX_FADVISE < 1
48#define LOC QString("FileRingBuf(%1): ").arg(m_filename)
50static const QStringList
kSubExt {
".ass",
".srt",
".ssa",
".sub",
".txt"};
51static const QStringList
kSubExtNoCheck {
".ass",
".srt",
".ssa",
".sub",
".txt",
".gif",
".png"};
68 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Failed to open remote file (%1) for write").arg(
m_filename));
91 else if (Timeout >= 0ms)
120 QFileInfo fileInfo(Filename);
121 if (fileInfo.exists() && !fileInfo.isReadable())
123 LOG(VB_GENERAL, LOG_ERR, QString(
"FileRingBuf(%1): File exists but is not readable by MythTV!")
133 [Extension] (
const QString& ext) ->
bool
134 {
return ext.contains(Extension);});
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);
153 const QString findBaseName = baseName.replace(
"[",
"?")
158 for (
const auto & ext :
kSubExt)
159 list += findBaseName + ext;
165 dir.setPath(dirName);
166 const QStringList candidates = dir.entryList(list);
167 for (
const auto & candidate : candidates)
169 QFileInfo
file(dirName +
"/" + candidate);
171 return file.absoluteFilePath();
179 LOG(VB_PLAYBACK, LOG_INFO,
LOC + QString(
"OpenFile(%1, %2 ms)")
180 .arg(Filename).arg(Retry.count()));
200 bool islocal = (!
m_filename.startsWith(
"/dev")) &&
205 std::array<char,kReadTestSize> buf {};
211 uint openAttempts = 0;
212 while ((openTimer.
elapsed() < Retry) || (openAttempts == 0))
229 std::this_thread::sleep_for(10ms);
233 ssize_t ret =
read(
m_fd2, buf.data(), buf.size());
247 std::this_thread::sleep_for(10ms);
251 if (0 == lseek(
m_fd2, 0, SEEK_SET))
255 LOG(VB_FILE, LOG_DEBUG,
LOC +
256 QString(
"OpenFile(): fadvise sequential "
261 LOG(VB_FILE, LOG_DEBUG,
LOC +
262 QString(
"OpenFile(): fadvise willneed "
279 QString extension =
file.completeSuffix().toLower();
285 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"OpenFile(): Could not open."));
290 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"OpenFile(): File too small (%1B).")
296 LOG(VB_GENERAL, LOG_ERR,
LOC +
"OpenFile(): Improper permissions.");
300 LOG(VB_GENERAL, LOG_ERR,
LOC +
"OpenFile(): Cannot seek in file.");
305 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"OpenFile() made %1 attempts in %2 ms")
306 .arg(openAttempts).arg(openTimer.
elapsed().count()));
311 QString dirName =
".";
313 int dirPos =
m_filename.lastIndexOf(QChar(
'/'));
320 QStringList auxFiles;
322 int suffixPos = tmpSubName.lastIndexOf(QChar(
'.'));
325 QString baseName = tmpSubName.left(suffixPos);
326 int extnleng = tmpSubName.size() - baseName.size() - 1;
327 QString extension = tmpSubName.right(extnleng);
331 auxFiles.reserve(
kSubExt.size());
332 for (
const auto & ext :
kSubExt)
333 auxFiles += baseName + ext;
340 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"RingBuffer::RingBuffer(): Failed to open remote file (%1)")
369 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Tried to ReOpen a read only file.");
430 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Invalid file descriptor in 'safe_read()'");
441 uint toread = Size - tot;
448 int ret = fstat(
m_fd2, &sb);
449 if (ret == 0 && S_ISREG(sb.st_mode))
456 LOG(VB_FILE, LOG_DEBUG,
LOC +
"not reading, reached EOF");
460 toread =
static_cast<uint>(std::min(sb.st_size - (
m_internalReadPos + tot),
static_cast<long long>(toread)));
461 if (toread < (Size - tot))
464 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"About to reach EOF, reading %1 wanted %2")
465 .arg(toread).arg(Size-tot));
472 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"read(%1) -- begin").arg(toread));
473 ret =
static_cast<int>(
read(
m_fd2,
static_cast<char*
>(
Buffer) + tot, toread));
474 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"read(%1) -> %2 end").arg(toread).arg(ret));
481 LOG(VB_GENERAL, LOG_ERR,
LOC +
"File I/O problem in 'safe_read()'" +
ENO);
489 tot +=
static_cast<uint>(ret);
519 std::this_thread::sleep_for(60ms);
521 return static_cast<int>(tot);
534 int ret = Remote->
Read(
Buffer,
static_cast<int>(Size));
537 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read(RemoteFile* ...): read failed");
540 LOG(VB_GENERAL, LOG_ERR,
LOC +
"safe_read() failed to seek reset");
546 LOG(VB_FILE, LOG_INFO,
LOC +
"safe_read(RemoteFile* ...): at EOF");
563 long long result = -1;
574 result = fstat(
m_fd2, &sb);
575 if (result == 0 && S_ISREG(sb.st_mode))
602 (Whence == SEEK_CUR && Position == 0)))
610 long long newposition = (SEEK_SET==Whence) ? Position :
m_readPos + Position;
618 LOG(VB_FILE, LOG_INFO,
LOC +
619 QString(
"Seek(): rbrpos: %1 rbwpos: %2\n\t\t\treadpos: %3 internalreadpos: %4")
621 bool used_opt =
false;
628 internal_backbuf = std::min(internal_backbuf, free - min_safety);
630 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek(): internal_backbuf: %1 sba: %2")
631 .arg(internal_backbuf).arg(sba));
632 if (internal_backbuf >= sba)
637 LOG(VB_FILE, LOG_INFO,
LOC +
638 QString(
"Seek(): OPT1 rbrPos: %1 rbwPos: %2"
639 "\n\t\t\treadpos: %3 internalreadpos: %4")
648 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek(): OPT2 rbrPos: %1 sba: %2")
667 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);
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=[])