Go to the documentation of this file.
13 #include "mythconfig.h"
33 #include <sys/types.h>
40 #include "libavformat/avformat.h"
43 #define LOC QString("RingBuf(%1): ").arg(m_filename)
98 bool UseReadAhead, std::chrono::milliseconds Timeout,
bool StreamOnly)
108 bool httpurl = lower.startsWith(
"http://") || lower.startsWith(
"https://");
109 bool iptvurl = lower.startsWith(
"rtp://") || lower.startsWith(
"tcp://") ||
110 lower.startsWith(
"udp://");
111 bool mythurl = lower.startsWith(
"myth://");
112 bool bdurl = lower.startsWith(
"bd:");
113 bool dvdurl = lower.startsWith(
"dvd:");
114 bool imgext = lower.endsWith(
".img") || lower.endsWith(
".iso");
130 if (httpurl || iptvurl)
136 if (!StreamOnly && mythurl)
148 else if (!StreamOnly && !mythurl)
150 if (QFile::exists(
filename +
"/VIDEO_TS"))
152 else if (QFile::exists(
filename +
"/BDMV"))
156 if (!StreamOnly && (dvdurl || dvddir))
161 if (!(mythurl || QFile::exists(
filename)))
163 LOG(VB_PLAYBACK, LOG_INFO,
"Trying DVD at " +
filename);
167 if (!StreamOnly && (bdurl || bddir))
172 if (!(mythurl || QFile::exists(
filename)))
174 LOG(VB_PLAYBACK, LOG_INFO,
"Trying BD at " +
filename);
178 if (!mythurl && imgext &&
filename.startsWith(
"dvd:"))
180 LOG(VB_PLAYBACK, LOG_INFO,
"DVD image at " +
filename);
184 if (!mythurl && lower.endsWith(
".vob") &&
filename.contains(
"/VIDEO_TS/"))
186 LOG(VB_PLAYBACK, LOG_INFO,
"DVD VOB at " +
filename);
188 if (dvdstream && dvdstream->IsOpen())
238 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Reset(%1,%2,%3)")
239 .
arg(Full).
arg(ToAdjust).
arg(ResetInternal));
253 LOG(VB_GENERAL, LOG_ERR,
LOC +
254 QString(
"MythMediaBuffer::Reset() nonzero readpos. toAdjust: %1 "
255 "readpos: %2 readAdjust: %3")
279 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"UpdateRawBitrate(%1Kb)").
arg(RawBitrate));
285 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Bitrate too low - setting to 64Kb"));
288 else if (RawBitrate > 100000)
290 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Bitrate too high - setting to 100Mb"));
354 const uint KB2 = 2*1024;
355 const uint KB4 = 4*1024;
356 const uint KB8 = 8*1024;
357 const uint KB16 = 16*1024;
358 const uint KB32 = 32*1024;
359 const uint KB64 = 64*1024;
360 const uint KB128 = 128*1024;
361 const uint KB256 = 256*1024;
362 const uint KB512 = 512*1024;
366 int const rbs = (estbitrate > 18000) ? KB512 :
367 (estbitrate > 9000) ? KB256 :
368 (estbitrate > 5000) ? KB128 :
369 (estbitrate > 2500) ? KB64 :
370 (estbitrate > 1250) ? KB32 :
371 (estbitrate >= 500) ? KB16 :
372 (estbitrate > 250) ? KB8 :
373 (estbitrate > 125) ? KB4 : KB2;
380 float secs_min = 0.3F;
382 m_fillMin =
static_cast<int>((estbitrate * 1000 * secs_min) * 0.125F);
387 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Buffering optimisations disabled.");
395 LOG(VB_GENERAL, LOG_WARNING,
"Enabling buffering optimisations for low bitrate stream.");
398 LOG(VB_FILE, LOG_INFO,
LOC +
399 QString(
"CalcReadAheadThresh(%1 Kb)\n\t\t\t -> "
400 "threshold(%2 KB) min read(%3 KB) blk size(%4 KB)")
421 if (kbitspersec == 0)
424 double readahead_time = size / (kbitspersec * (1000.0 / 8.0));
426 bool near_end = readahead_time <= 1.5;
427 LOG(VB_PLAYBACK, LOG_INFO,
LOC +
"IsReallyNearEnd()" +
428 QString(
" br(%1KB)").
arg(kbitspersec/8) +
429 QString(
" sz(%1KB)").
arg(size / 1000LL) +
430 QString(
" vfl(%1)").
arg(Frames) +
431 QString(
" time(%1)").
arg(readahead_time) +
433 QString(
" avail(%1)").
arg(size) +
435 QString(
" readposition(%1)").
arg(readpos) +
438 QString(
" ne:%1").
arg(near_end));
474 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Seek: Position:%1 Type: %2 Locked: %3)")
476 .
arg((SEEK_SET == Whence) ?
"SEEK_SET" : ((SEEK_CUR == Whence) ?
"SEEK_CUR" :
"SEEK_END"))
477 .
arg(HasLock?
"locked":
"unlocked"));
537 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"SetReadInternalMode: %1").
arg(Mode ?
"on" :
"off"));
570 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"ResetReadAhead(internalreadpos = %1->%2)")
621 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Not starting read ahead thread - write only RingBuffer");
626 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Not starting read ahead thread - already running");
664 LOG(VB_FILE, LOG_INFO,
LOC +
"StopReads()");
674 LOG(VB_FILE, LOG_INFO,
LOC +
"StartReads()");
685 LOG(VB_FILE, LOG_INFO,
LOC +
"Pausing read ahead thread");
699 LOG(VB_FILE, LOG_INFO,
LOC +
"Unpausing readahead thread");
721 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Waited %1 ms for ringbuffer pause")
722 .
arg(
t.elapsed().count()));
804 m_rbwPos =
static_cast<int>(oldsize);
814 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Created readAheadBuffer: %1Mb")
815 .
arg(newsize >> 20));
823 std::chrono::milliseconds readTimeAvg = 300ms;
824 bool ignoreForReadTiming =
true;
827 auto lastread = nowAsDuration<std::chrono::milliseconds>();
846 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Initial readblocksize %1K fillMin %2K")
857 LOG(VB_FILE, LOG_WARNING,
LOC + QString(
"File not opened, terminating readahead thread"));
866 ignoreForReadTiming =
true;
867 LOG(VB_FILE, LOG_DEBUG,
LOC +
"run: PauseAndWait Not reading continuing");
873 const uint KB32 = 32*1024;
874 const int KB512 = 512*1024;
882 LOG(VB_FILE, LOG_DEBUG,
LOC +
883 QString(
"run: Not reading continuing: totfree(%1) "
884 "readsallowed(%2) ignorereadpos(%3) commserror(%4) "
895 ignoreForReadTiming =
true;
905 totfree = (totfree / KB32) * KB32;
910 auto now = nowAsDuration<std::chrono::milliseconds>();
911 if (!ignoreForReadTiming)
913 readTimeAvg = (readTimeAvg * 9 + (now - lastread)) / 10;
915 if (readTimeAvg < 150ms &&
925 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Avg read interval was %1 msec. "
926 "%2K -> %3K block size")
933 LOG(VB_FILE, LOG_INFO,
LOC +
934 QString(
"Avg read interval was %1 msec. %2K -> %3K block size")
935 .
arg(readTimeAvg.count())
947 LOG(VB_FILE, LOG_DEBUG,
LOC +
"Shrinking read, near end of buffer");
953 LOG(VB_FILE, LOG_DEBUG,
LOC +
"Reading enough data to start playback");
956 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"safe_read(...@%1, %2) -- begin")
970 int sr_elapsed = sr_timer.
elapsed().count();
971 uint64_t bps = !sr_elapsed ? 1000000001 :
972 static_cast<uint64_t
>((readResult * 8000.0) /
static_cast<double>(sr_elapsed));
973 LOG(VB_FILE, LOG_DEBUG,
LOC +
974 QString(
"safe_read(...@%1, %2) -> %3, took %4 ms %5 avg %6 ms")
975 .
arg(rbwposcopy).
arg(totfree).
arg(readResult).
arg(sr_elapsed)
976 .
arg(QString(
"(%1Mbps)").
arg(
static_cast<double>(bps) / 1000000.0))
977 .
arg(readTimeAvg.count()));
989 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"rbwpos += %1K requested %2K in read")
990 .
arg(readResult/1024,3).
arg(totfree/1024,3));
997 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"total read so far: %1 bytes")
1003 LOG(VB_FILE, LOG_DEBUG,
LOC +
1004 QString(
"We are not reading anything (totfree: %1 commserror:%2 ateof:%3 setswitchtonext:%4")
1011 ignoreForReadTiming = (totfree <
m_readBlockSize) || (readResult < totfree);
1029 if ((0 == readResult) && (oldreadposition ==
m_readPos))
1051 LOG(VB_FILE, LOG_DEBUG,
LOC +
1052 QString(
"EOF encountered, but %1 still being written to")
1062 LOG(VB_FILE, LOG_DEBUG,
LOC +
1063 QString(
"EOF encountered, but %1 still being written to")
1075 LOG(VB_FILE, LOG_DEBUG,
LOC +
"Waiting for file to grow large enough to process.");
1080 LOG(VB_FILE, LOG_DEBUG,
LOC +
"setting ateof (readResult == 0)");
1095 LOG(VB_FILE, LOG_DEBUG,
LOC +
"@ end of read ahead loop");
1098 (m_wantToRead <= used && m_wantToRead > 0))
1105 std::this_thread::sleep_for(5ms);
1122 std::this_thread::sleep_for(5ms);
1147 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Exiting readahead thread"));
1167 if (result != Count)
1169 LOG(VB_GENERAL, LOG_WARNING,
LOC + QString(
"Peek requested %1 bytes but only have %2")
1170 .
arg(Count).
arg(result));
1185 std::chrono::milliseconds timeoutms = 30s;
1193 std::chrono::milliseconds delta =
clamp(timeoutms - timer.
elapsed(), 10ms, 100ms);
1195 if (!check && timer.
elapsed() > 1s && (count % 100) == 0)
1196 LOG(VB_GENERAL, LOG_WARNING,
LOC +
"Taking too long to be allowed to read..");
1200 if (timer.
elapsed() >= timeoutms)
1202 LOG(VB_GENERAL, LOG_ERR,
LOC + QString(
"Took more than %1 seconds to be allowed to read, aborting.")
1203 .
arg(duration_cast<std::chrono::seconds>(timeoutms).count()));
1212 if (available >= Count)
1215 Count = (
m_ateof && available < Count) ? available : Count;
1230 std::chrono::milliseconds delta =
clamp(Timeout - timer.
elapsed(), 10ms, 250ms);
1237 if (timer.
elapsed() > Timeout)
1247 long long oldposition = 0;
1258 int elapsed = timer.
elapsed().count();
1259 uint64_t bps = !elapsed ? 1000000001 :
static_cast<uint64_t
>((result * 8000.0) /
static_cast<double>(elapsed));
1268 long long cur_pos = -1;
1271 else if (
m_fd2 >= 0)
1272 cur_pos = lseek64(
m_fd2, oldposition, SEEK_SET);
1275 LOG(VB_FILE, LOG_ERR,
LOC +
"Seek failed repositioning to previous position");
1287 if (
Peek && (result > 0))
1289 if ((
IsDVD() ||
IsBD()) && oldposition != 0)
1291 LOG(VB_GENERAL, LOG_ERR,
LOC +
1292 "DVD and Blu-Ray do not support arbitrary "
1293 "peeks except when read-ahead is enabled."
1294 "\n\t\t\tWill seek to beginning of video.");
1298 long long newposition =
Seek(oldposition, SEEK_SET,
true);
1300 if (newposition != oldposition)
1302 LOG(VB_GENERAL, LOG_ERR,
LOC +
1303 QString(
"Peek() Failed to return from new position %1 to old position %2, now "
1305 .
arg(oldposition - result).
arg(oldposition).
arg(newposition));
1322 QString desc = QString(
"ReadPriv(..%1, %2)").arg(Count).arg(
Peek ?
"peek" :
"normal");
1328 LOG(VB_GENERAL, LOG_ERR,
LOC + desc +
": Attempt to read from a write only file");
1346 LOG(VB_FILE, LOG_DEBUG,
LOC + desc + QString(
": ReadDirect checksum %1")
1347 .
arg(qChecksum(
reinterpret_cast<char*
>(
Buffer),
static_cast<uint>(Count))));
1357 LOG(VB_FILE, LOG_NOTICE,
LOC + desc +
": !WaitForReadsAllowed()");
1370 std::chrono::milliseconds timeout_ms = 10s;
1377 LOG(VB_GENERAL, LOG_INFO,
LOC +
"Checking to see if there's a new livetv program to switch to..");
1386 LOG(VB_GENERAL, LOG_WARNING,
LOC + desc + QString(
" -- waited %1 ms for avail(%2) > count(%3)")
1387 .
arg(timer.
elapsed().count()).arg(available).arg(Count));
1392 LOG(VB_FILE, LOG_DEBUG,
LOC + QString(
"ReadPriv: %1 bytes available, %2 left")
1408 LOG(VB_GENERAL, LOG_ERR,
LOC + desc + QString(
" -- timed out waiting for data (%1 ms)")
1426 LOG(VB_FILE, LOG_DEBUG,
LOC + desc +
": Copying data");
1428 int readposition = 0;
1434 if (readposition + Count >
static_cast<int>(
m_bufferSize))
1436 int firstsize =
static_cast<int>(
m_bufferSize) - readposition;
1437 int secondsize = Count - firstsize;
1446 LOG(VB_FILE, LOG_DEBUG,
LOC + desc + QString(
": Checksum %1")
1447 .
arg(qChecksum(
reinterpret_cast<char*
>(
Buffer),
static_cast<uint>(Count))));
1494 if (Rate > 1000000000)
1495 return QObject::tr(
">1Gbps");
1498 auto bitrate =
static_cast<double>(NAN);
1499 auto rate =
static_cast<double>(Rate);
1502 if (Rate >= 1000000)
1504 msg = Hz ? QObject::tr(
"%1MHz") : QObject::tr(
"%1Mbps");
1505 bitrate = rate / 1000000.0;
1508 else if (Rate >= 1000)
1510 msg = Hz ? QObject::tr(
"%1kHz") : QObject::tr(
"%1kbps");
1511 bitrate = rate / 1000.0;
1516 msg = Hz ? QObject::tr(
"%1Hz") : QObject::tr(
"%1bps");
1519 return msg.arg(bitrate, 0,
'f', range);
1539 return QString(
"%1%").arg(lroundf((
static_cast<float>(avail) /
static_cast<float>(
m_bufferSize) * 100.0F)));
1552 auto current = std::chrono::milliseconds(QDateTime::currentDateTime().toMSecsSinceEpoch());
1553 std::chrono::milliseconds expire =
current - 1s;
1559 QMutableMapIterator<std::chrono::milliseconds,uint64_t> it(
m_decoderReads);
1560 while (it.hasNext())
1563 if (it.key() < expire || it.key() >
current)
1566 total += it.value();
1572 auto average =
static_cast<uint64_t
>(
static_cast<double>(total) * 8.0);
1573 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Decoder read speed: %1 %2")
1574 .
arg(average).
arg(size));
1583 auto current = std::chrono::milliseconds(QDateTime::currentDateTime().toMSecsSinceEpoch());
1590 QMutableMapIterator<std::chrono::milliseconds,uint64_t> it(
m_storageReads);
1591 while (it.hasNext())
1594 if (it.key() < expire || it.key() >
current)
1597 total += it.value();
1603 uint64_t average = size ?
static_cast<uint64_t
>(
static_cast<double>(total) / size) : 0;
1604 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"Average storage read speed: %1 (Reads %2")
1620 LOG(VB_GENERAL, LOG_ERR,
LOC +
"Tried to write to a read only file.");
1662 long long result = -1;
1722 LOG(VB_FILE, LOG_INFO,
LOC + QString(
"SetOldFile: %1)").
arg(Old));
1851 static QMutex s_avnetworkLock(QMutex::Recursive);
1852 static bool s_avnetworkInitialised =
false;
1853 QMutexLocker lock(&s_avnetworkLock);
1854 if (!s_avnetworkInitialised)
1856 avformat_network_init();
1857 s_avnetworkInitialised =
true;
std::chrono::milliseconds elapsed(void)
Returns milliseconds elapsed since last start() or restart()
QFileInfo fileInfo(filename)
long long Seek(long long pos, int whence)
Seek to a position within stream; May be unsafe.
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
void Sync(void) const
Flush data written to the file descriptor to disk.
A QElapsedTimer based timer to replace use of QTime as a timer.
static bool TestForHTTPLiveStreaming(const QString &filename)
static bool Exists(const QString &url, struct stat *fileinfo)
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
arg(title).arg(filename).arg(doDelete))
void Flush(void)
Allow DiskLoop() to flush buffer completely ignoring low watermark.
void start(void)
starts measuring elapsed time.
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
int Write(const void *data, int size)
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
bool IsRegisteredFileForWrite(const QString &file)
long long Seek(long long pos, int whence, long long curpos=-1)
float clamp(float val, float minimum, float maximum)
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
void ReloadAll(const QStringList &data=QStringList())
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
int Write(const void *data, uint count)
Writes data to the end of the write buffer.
static ImageType inspectImage(const QString &path)
void SwitchToNext(bool up)
Sets the recording to switch to.
This is a wrapper around QThread that does several additional things.
bool isRunning(void) const
bool SetBlocking(bool block=true)
Set write blocking mode While in blocking mode, ThreadedFileWriter::Write will wait for buffers to be...
Keeps track of recordings in a current LiveTV instance.