+
+RESULT eDVBChannel::playFile(const char *file)
+{
+ ASSERT(!m_frontend);
+ if (m_pvr_thread)
+ {
+ m_pvr_thread->stop();
+ delete m_pvr_thread;
+ m_pvr_thread = 0;
+ }
+
+ m_tstools.openFile(file);
+
+ /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
+ THEN DO A REAL FIX HERE! */
+
+ /* (this codepath needs to be improved anyway.) */
+ m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
+ if (m_pvr_fd_dst < 0)
+ {
+ eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
+ return -ENODEV;
+ }
+
+ m_pvr_fd_src = open(file, O_RDONLY);
+ if (m_pvr_fd_src < 0)
+ {
+ eDebug("can't open PVR m_pvr_fd_src file %s (%m)", file);
+ close(m_pvr_fd_dst);
+ return -ENOENT;
+ }
+
+ m_state = state_ok;
+ m_stateChanged(this);
+
+ m_pvr_thread = new eFilePushThread();
+ m_pvr_thread->start(m_pvr_fd_src, m_pvr_fd_dst);
+
+ return 0;
+}
+
+RESULT eDVBChannel::getLength(pts_t &len)
+{
+ return m_tstools.calcLen(len);
+}
+
+RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos)
+{
+ if (!decoding_demux)
+ return -1;
+
+ off_t begin = 0;
+ /* getPTS for offset 0 is cached, so it doesn't harm. */
+ int r = m_tstools.getPTS(begin, pos);
+ if (r)
+ {
+ eDebug("tstools getpts(0) failed!");
+ return r;
+ }
+
+ pts_t now;
+
+ r = decoding_demux->getSTC(now);
+
+ if (r)
+ {
+ eDebug("demux getSTC failed");
+ return -1;
+ }
+
+// eDebug("STC: %08llx PTS: %08llx, diff %lld", now, pos, now - pos);
+ /* when we are less than 10 seconds before the start, return 0. */
+ /* (we're just waiting for the timespam to start) */
+ if ((now < pos) && ((pos - now) < 90000 * 10))
+ {
+ pos = 0;
+ return 0;
+ }
+
+ if (now < pos) /* wrap around */
+ pos = now + ((pts_t)1)<<33 - pos;
+ else
+ pos = now - pos;
+
+ return 0;
+}
+
+RESULT eDVBChannel::seekTo(iDVBDemux *decoding_demux, int relative, pts_t &pts)
+{
+ int bitrate = m_tstools.calcBitrate(); /* in bits/s */
+
+ if (bitrate == -1)
+ return -1;
+
+ if (relative)
+ {
+ pts_t now;
+ if (getCurrentPosition(decoding_demux, now))
+ {
+ eDebug("seekTo: getCurrentPosition failed!");
+ return -1;
+ }
+ pts += now;
+ }
+
+ if (pts < 0)
+ pts = 0;
+
+ off_t offset = (pts * (pts_t)bitrate) / 8ULL / 90000ULL;
+
+ seekToPosition(decoding_demux, offset);
+ return 0;
+}
+
+RESULT eDVBChannel::seekToPosition(iDVBDemux *decoding_demux, const off_t &r)
+{
+ /* when seeking, we have to ensure that all buffers are flushed.
+ there are basically 3 buffers:
+ a.) the filepush's internal buffer
+ b.) the PVR buffer (before demux)
+ c.) the ratebuffer (after demux)
+
+ it's important to clear them in the correct order, otherwise
+ the ratebuffer (for example) would immediately refill from
+ the not-yet-flushed PVR buffer.
+ */
+ eDebug("eDVBChannel: seekToPosition .. %llx", r);
+ m_pvr_thread->pause();
+
+ /* flush internal filepush buffer */
+ m_pvr_thread->flush();
+
+ /* HACK: flush PVR buffer */
+ ::ioctl(m_pvr_fd_dst, 0);
+
+ /* flush ratebuffers (video, audio) */
+ if (decoding_demux)
+ decoding_demux->flush();
+
+ /* demux will also flush all decoder.. */
+ m_pvr_thread->seek(SEEK_SET, r);
+ m_pvr_thread->resume();
+ return 0;
+}