[Timeshift] write .sc file during timeshift to improve rewind/fastforward(16x)
authorhschang <chang@dev3>
Tue, 8 Dec 2015 06:33:16 +0000 (15:33 +0900)
committerhschang <chang@dev3>
Tue, 8 Dec 2015 06:33:16 +0000 (15:33 +0900)
lib/dvb/demux.cpp
lib/dvb/demux.h
lib/dvb/idemux.h
lib/dvb/pvrparse.cpp
lib/dvb/pvrparse.h
lib/dvb/tstools.cpp
lib/service/servicedvb.cpp

index f4d8618..0d03927 100644 (file)
@@ -453,6 +453,7 @@ public:
        
        void startSaveMetaInformation(const std::string &filename);
        void stopSaveMetaInformation();
+       void enableAccessPoints(bool enable);
        int getLastPTS(pts_t &pts);
 protected:
        int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
@@ -485,6 +486,11 @@ void eDVBRecordFileThread::stopSaveMetaInformation()
        m_stream_info.stopSave();
 }
 
+void eDVBRecordFileThread::enableAccessPoints(bool enable)
+{
+       m_ts_parser.enableAccessPoints(enable);
+}
+
 int eDVBRecordFileThread::getLastPTS(pts_t &pts)
 {
        return m_ts_parser.getLastPTS(pts);
@@ -648,6 +654,12 @@ RESULT eDVBTSRecorder::setTargetFilename(const char *filename)
        return 0;
 }
 
+RESULT eDVBTSRecorder::enableAccessPoints(bool enable)
+{
+       m_thread->enableAccessPoints(enable);
+       return 0;
+}
+
 RESULT eDVBTSRecorder::setBoundary(off_t max)
 {
        return -1; // not yet implemented
index e73982e..ca7fc4d 100644 (file)
@@ -101,6 +101,7 @@ public:
        
        RESULT setTargetFD(int fd);
        RESULT setTargetFilename(const char *filename);
+       RESULT enableAccessPoints(bool enable);
        RESULT setBoundary(off_t max);
        
        RESULT stop();
index 86b35fd..0cb82cf 100644 (file)
@@ -38,6 +38,7 @@ public:
        virtual RESULT setTargetFD(int fd) = 0;
                /* for saving additional meta data. */
        virtual RESULT setTargetFilename(const char *filename) = 0;
+       virtual RESULT enableAccessPoints(bool enable) = 0;
        virtual RESULT setBoundary(off_t max) = 0;
        
        virtual RESULT stop() = 0;
index c5a5c9c..173a774 100755 (executable)
@@ -7,7 +7,7 @@
 #endif
 
 eMPEGStreamInformation::eMPEGStreamInformation()
-       : m_structure_cache_valid(0), m_structure_read(0), m_structure_write(0)
+       : m_structure_cache_entries(0), m_structure_read(0), m_structure_write(0)
 {
 }
 
@@ -33,6 +33,10 @@ int eMPEGStreamInformation::stopSave(void)
                fclose(m_structure_write);
                m_structure_write = 0;
        }
+
+       if (m_access_points.empty())
+               return 0;
+
        if (m_filename == "")
                return -1;
        FILE *f = fopen((m_filename + ".ap").c_str(), "wb");
@@ -62,11 +66,12 @@ int eMPEGStreamInformation::load(const char *filename)
        if (m_structure_read)
                fclose(m_structure_read);
        m_structure_read = fopen((std::string(m_filename) + ".sc").c_str(), "rb");
+       m_access_points.clear();
+       m_pts_to_offset.clear();
+       m_timestamp_deltas.clear();
        FILE *f = fopen((std::string(m_filename) + ".ap").c_str(), "rb");
        if (!f)
                return -1;
-       m_access_points.clear();
-       m_pts_to_offset.clear();
        while (1)
        {
                unsigned long long d[2];
@@ -85,11 +90,6 @@ int eMPEGStreamInformation::load(const char *filename)
        return 0;
 }
 
-bool eMPEGStreamInformation::empty()
-{
-       return m_access_points.empty();
-}
-
 void eMPEGStreamInformation::fixupDiscontinuties()
 {
        m_timestamp_deltas.clear();
@@ -338,75 +338,21 @@ int eMPEGStreamInformation::getStructureEntry(off_t &offset, unsigned long long
                return -1;
        }
 
-       const int struture_cache_entries = sizeof(m_structure_cache) / 16;
-       if ((!m_structure_cache_valid) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(struture_cache_entries - (get_next ? 2 : 1)) * 2] <= offset))
+       off_t _offset = offset;
+       const int struture_cache_size = sizeof(m_structure_cache) / 16;
+       if ((m_structure_cache_entries == 0) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(m_structure_cache_entries - (get_next ? 2 : 1)) * 2] <= offset))
        {
-               fseek(m_structure_read, 0, SEEK_END);
-               int l = ftell(m_structure_read);
-               unsigned long long d[2];
-               const int entry_size = sizeof d;
-
-                       /* do a binary search */
-               int count = l / entry_size;
-               int i = 0;
-               
-               while (count)
-               {
-                       int step = count >> 1;
-                       
-                       fseek(m_structure_read, (i + step) * entry_size, SEEK_SET);
-                       if (!fread(d, 1, entry_size, m_structure_read))
-                       {
-                               eDebug("read error at entry %d", i);
-                               return -1;
-                       }
-                       
-#if BYTE_ORDER != BIG_ENDIAN
-                       d[0] = bswap_64(d[0]);
-                       d[1] = bswap_64(d[1]);
-#endif
-//                     eDebug("%d: %08llx > %llx", i, d[0], d[1]);
-                       
-                       if (d[0] < (unsigned long long)offset)
-                       {
-                               i += step + 1;
-                               count -= step + 1;
-                       } else
-                               count = step;
-               }
-               
-               eDebug("found %d", i);
-               
-                       /* put that in the middle */
-               i -= struture_cache_entries / 2;
-               if (i < 0)
-                       i = 0;
-               eDebug("cache starts at %d", i);
-               fseek(m_structure_read, i * entry_size, SEEK_SET);
-               int num = fread(m_structure_cache, entry_size, struture_cache_entries, m_structure_read);
-               eDebug("%d entries", num);
-               for (i = 0; i < struture_cache_entries; ++i)
+               if(update_structure_cache_entries(_offset))
                {
-                       if (i < num)
-                       {
-#if BYTE_ORDER != BIG_ENDIAN
-                               m_structure_cache[i * 2] = bswap_64(m_structure_cache[i * 2]);
-                               m_structure_cache[i * 2 + 1] = bswap_64(m_structure_cache[i * 2 + 1]);
-#endif
-                       } else
-                       {
-                               m_structure_cache[i * 2] = 0x7fffffffffffffffULL; /* fill with harmless content */
-                               m_structure_cache[i * 2 + 1] = 0;
-                       }
+                       return -1;
                }
-               m_structure_cache_valid = 1;
        }
        
        int i = 0;
        while ((off_t)m_structure_cache[i * 2] <= offset)
        {
                ++i;
-               if (i == struture_cache_entries)
+               if (i == m_structure_cache_entries)
                {
                        eDebug("structure data consistency fail!, we are looking for %llx, but last entry is %llx", offset, m_structure_cache[i*2-2]);
                        return -1;
@@ -436,8 +382,7 @@ int eMPEGStreamInformation::getStructureEntry_next(off_t &offset, unsigned long
        }
 
        off_t _offset = offset;
-       const int struture_cache_entries = sizeof(m_structure_cache) / 16;
-       if ((!m_structure_cache_valid) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(struture_cache_entries - 1)*2] <= offset))
+       if ((m_structure_cache_entries == 0) || ((off_t)m_structure_cache[0] > offset) || ((off_t)m_structure_cache[(m_structure_cache_entries - 1)*2] <= offset))
        {
                if(update_structure_cache_entries(_offset))
                {
@@ -449,9 +394,9 @@ int eMPEGStreamInformation::getStructureEntry_next(off_t &offset, unsigned long
        while ((off_t)m_structure_cache[i * 2] <= offset)
        {
                ++i;
-               if (i == struture_cache_entries)
+               if (i == m_structure_cache_entries)
                {
-                       eDebug("structure data consistency fail!, we are looking for %llu, but last entry is %llu", offset, m_structure_cache[(struture_cache_entries-1)*2]);
+                       eDebug("structure data consistency fail!, we are looking for %llu, but last entry is %llu", offset, m_structure_cache[(m_structure_cache_entries-1)*2]);
                        return -1;
                }
        }
@@ -476,8 +421,7 @@ int eMPEGStreamInformation::getStructureEntry_prev(off_t &offset, unsigned long
        }
 
        off_t _offset = offset;
-       const int struture_cache_entries = sizeof(m_structure_cache) / 16;
-       if ((!m_structure_cache_valid) || ((off_t)m_structure_cache[0] >= offset) || ((off_t)m_structure_cache[(struture_cache_entries - 1)*2] < offset))
+       if ((m_structure_cache_entries == 0) || ((off_t)m_structure_cache[0] >= offset) || ((off_t)m_structure_cache[(m_structure_cache_entries - 1)*2] < offset))
        {
                if(update_structure_cache_entries(_offset))
                {
@@ -485,7 +429,7 @@ int eMPEGStreamInformation::getStructureEntry_prev(off_t &offset, unsigned long
                }
        }
 
-       int i = struture_cache_entries-1;
+       int i = m_structure_cache_entries-1;
        while ((off_t)m_structure_cache[i * 2] >= offset)
        {
                if (i <= 0)
@@ -495,7 +439,7 @@ int eMPEGStreamInformation::getStructureEntry_prev(off_t &offset, unsigned long
                }
                --i;
        }
-       if (i == struture_cache_entries-1)
+       if (i == m_structure_cache_entries-1)
        {
                eDebug("structure data (first entry) consistency fail!");
                return -1;
@@ -509,7 +453,7 @@ int eMPEGStreamInformation::getStructureEntry_prev(off_t &offset, unsigned long
 
 int eMPEGStreamInformation::update_structure_cache_entries(off_t offset)
 {
-       const int struture_cache_entries = sizeof(m_structure_cache) / 16;
+       const int struture_cache_size = sizeof(m_structure_cache) / 16;
        fseek(m_structure_read, 0, SEEK_END);
        int l = ftell(m_structure_read);
        unsigned long long d[2];
@@ -543,14 +487,14 @@ int eMPEGStreamInformation::update_structure_cache_entries(off_t offset)
        eDebug("found %d", i);
 
        /* put that in the middle */
-       i -= struture_cache_entries / 2;
+       i -= struture_cache_size / 2;
        if (i < 0)
                i = 0;
        eDebug("cache starts at %d", i);
        fseek(m_structure_read, i * entry_size, SEEK_SET);
-       int num = fread(m_structure_cache, entry_size, struture_cache_entries, m_structure_read);
+       int num = fread(m_structure_cache, entry_size, struture_cache_size, m_structure_read);
        eDebug("%d entries", num);
-       for (i = 0; i < struture_cache_entries; ++i)
+       for (i = 0; i < struture_cache_size; ++i)
        {
                if (i < num)
                {
@@ -564,11 +508,18 @@ int eMPEGStreamInformation::update_structure_cache_entries(off_t offset)
                        m_structure_cache[i * 2 + 1] = 0x7fffffffffffffffULL;
                }
        }
-       m_structure_cache_valid = 1;
+       m_structure_cache_entries = num;
        return 0;
 }
 
-eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo): m_streaminfo(streaminfo), m_pktptr(0), m_pid(-1), m_need_next_packet(0), m_skip(0), m_last_pts_valid(0)
+eMPEGStreamParserTS::eMPEGStreamParserTS(eMPEGStreamInformation &streaminfo):
+       m_streaminfo(streaminfo),
+       m_pktptr(0),
+       m_pid(-1),
+       m_need_next_packet(0),
+       m_skip(0),
+       m_last_pts_valid(0),
+       m_enable_accesspoints(true)
 {
 }
 
@@ -652,14 +603,17 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
                                        unsigned long long data = sc | (pkt[4] << 8) | (pkt[5] << 16) | (pkt[6] << 24);
                                        m_streaminfo.writeStructureEntry(offset + pkt_offset, data  & 0xFFFFFFFFULL);
                                }
-                               if (pkt[3] == 0xb3) /* sequence header */
+                               if (m_enable_accesspoints)
                                {
-                                       if (ptsvalid)
+                                       if (pkt[3] == 0xb3) /* sequence header */
                                        {
-                                               m_streaminfo.m_access_points[offset] = pts;
-       //                                      eDebug("Sequence header at %llx, pts %llx", offset, pts);
-                                       } else
-                                               /*eDebug("Sequence header but no valid PTS value.")*/;
+                                               if (ptsvalid)
+                                               {
+                                                       m_streaminfo.m_access_points[offset] = pts;
+               //                                      eDebug("Sequence header at %llx, pts %llx", offset, pts);
+                                               } else
+                                                       /*eDebug("Sequence header but no valid PTS value.")*/;
+                                       }
                                }
                        }
 
@@ -671,15 +625,18 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
                                        unsigned long long data = sc | (pkt[4] << 8);
                                        m_streaminfo.writeStructureEntry(offset + pkt_offset, data);
                                }
-                               if (pkt[3] == 0x09 &&   /* MPEG4 AVC NAL unit access delimiter */
-                                        (pkt[4] >> 5) == 0) /* and I-frame */
+                               if (m_enable_accesspoints)
                                {
-                                       if (ptsvalid)
+                                       if (pkt[3] == 0x09 &&   /* MPEG4 AVC NAL unit access delimiter */
+                                                (pkt[4] >> 5) == 0) /* and I-frame */
                                        {
-                                               m_streaminfo.m_access_points[offset] = pts;
-       //                              eDebug("MPEG4 AVC UAD at %llx, pts %llx", offset, pts);
-                                       } else
-                                               /*eDebug("MPEG4 AVC UAD but no valid PTS value.")*/;
+                                               if (ptsvalid)
+                                               {
+                                                       m_streaminfo.m_access_points[offset] = pts;
+               //                              eDebug("MPEG4 AVC UAD at %llx, pts %llx", offset, pts);
+                                               } else
+                                                       /*eDebug("MPEG4 AVC UAD but no valid PTS value.")*/;
+                                       }
                                }
                        }
                        if (m_streamtype == 6) /* H.265 */
@@ -690,11 +647,14 @@ int eMPEGStreamParserTS::processPacket(const unsigned char *pkt, off_t offset)
                                        unsigned long long data = sc | (pkt[5] << 8);
                                        m_streaminfo.writeStructureEntry(offset + pkt_offset, data);
 
-                                       if ((pkt[5] >> 5) == 0) /* check pic_type for I-frame */
+                                       if (m_enable_accesspoints)
                                        {
-                                               if (ptsvalid)
+                                               if ((pkt[5] >> 5) == 0) /* check pic_type for I-frame */
                                                {
-                                                       m_streaminfo.m_access_points[offset] = pts;
+                                                       if (ptsvalid)
+                                                       {
+                                                               m_streaminfo.m_access_points[offset] = pts;
+                                                       }
                                                }
                                        }
                                }
index fa931a3..a15bbaf 100755 (executable)
@@ -47,8 +47,10 @@ public:
        off_t getAccessPoint(pts_t ts, int marg=0);
        
        int getNextAccessPoint(pts_t &ts, const pts_t &start, int direction);
-       
-       bool empty();
+
+       bool hasAccessPoint() { return !m_access_points.empty(); }
+
+       bool hasStructure() { return !m_structure_read ? false : true; }
        
        typedef unsigned long long structure_data;
                /* this is usually:
@@ -66,7 +68,7 @@ public:
        int update_structure_cache_entries(off_t offset);
 
        std::string m_filename;
-       int m_structure_cache_valid;
+       int m_structure_cache_entries;
        unsigned long long m_structure_cache[1024];
        FILE *m_structure_read, *m_structure_write;
 };
@@ -79,6 +81,7 @@ public:
        void parseData(off_t offset, const void *data, unsigned int len);
        void setPid(int pid, int streamtype);
        int getLastPTS(pts_t &last_pts);
+       void enableAccessPoints(bool enable) { m_enable_accesspoints = enable; }
 private:
        eMPEGStreamInformation &m_streaminfo;
        unsigned char m_pkt[188];
@@ -90,6 +93,7 @@ private:
        int m_skip;
        int m_last_pts_valid;
        pts_t m_last_pts;
+       bool m_enable_accesspoints;
 };
 
 #endif
index 379df9b..aefc3b5 100755 (executable)
@@ -57,7 +57,7 @@ void eDVBTSTools::setSource(ePtr<iTsSource> &source, const char *stream_info_fil
                m_streaminfo.load(stream_info_filename);
        }
        
-       if (!m_streaminfo.empty())
+       if (m_streaminfo.hasAccessPoint())
                m_use_streaminfo = 1;
        else
        {
@@ -655,7 +655,7 @@ int eDVBTSTools::findFrame(off_t &_iframe_offset, off_t &_new_offset, size_t &le
        int is_mpeg = 0;
 //     eDebug("trying to find iFrame at %lld", offset);
 
-       if (!m_use_streaminfo)
+       if (!m_streaminfo.hasStructure())
        {
 //             eDebug("can't get next iframe without streaminfo");
                return -1;
index 7005c84..d3c6032 100755 (executable)
@@ -1328,7 +1328,7 @@ RESULT eDVBServicePlay::setFastForward_internal(int ratio, bool final_seek)
                if (m_cue)
                {
                        long long _skipmode = skipmode;
-                       if (!m_timeshift_active && (m_current_video_pid_type == eDVBServicePMTHandler::videoStream::vtH265_HEVC))
+                       if (m_current_video_pid_type == eDVBServicePMTHandler::videoStream::vtH265_HEVC)
                        {
                                if (ratio < 0)
                                        _skipmode = skipmode * 3;
@@ -2228,6 +2228,8 @@ RESULT eDVBServicePlay::startTimeshift()
        }
                
        m_record->setTargetFD(m_timeshift_fd);
+       m_record->setTargetFilename(m_timeshift_file.c_str());
+       m_record->enableAccessPoints(false);
 
        m_timeshift_enabled = 1;
        
@@ -2253,6 +2255,11 @@ RESULT eDVBServicePlay::stopTimeshift(bool swToLive)
        close(m_timeshift_fd);
        eDebug("remove timeshift file");
        eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
+
+       {
+               std::string timeshift_file_sc = m_timeshift_file + ".sc";
+               eBackgroundFileEraser::getInstance()->erase(timeshift_file_sc.c_str());
+       }
        
        return 0;
 }
@@ -2349,6 +2356,8 @@ void eDVBServicePlay::updateTimeshiftPids()
                return;
        else
        {
+               int timing_pid = -1;
+               int timing_pid_type = -1;
                std::set<int> pids_to_record;
                pids_to_record.insert(0); // PAT
                if (program.pmtPid != -1)
@@ -2360,12 +2369,28 @@ void eDVBServicePlay::updateTimeshiftPids()
                for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
                        i(program.videoStreams.begin()); 
                        i != program.videoStreams.end(); ++i)
+               {
                        pids_to_record.insert(i->pid);
 
+                       if (timing_pid == -1)
+                       {
+                               timing_pid = i->pid;
+                               timing_pid_type = i->type;
+                       }
+               }
+
                for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
                        i(program.audioStreams.begin()); 
                        i != program.audioStreams.end(); ++i)
-                               pids_to_record.insert(i->pid);
+               {
+                       pids_to_record.insert(i->pid);
+
+                       if (timing_pid == -1)
+                       {
+                               timing_pid = i->pid;
+                               timing_pid_type = -1;
+                       }
+               }
 
                for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
                        i(program.subtitleStreams.begin());
@@ -2389,6 +2414,9 @@ void eDVBServicePlay::updateTimeshiftPids()
 
                for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
                        m_record->removePID(*i);
+
+               if (timing_pid != -1)
+                       m_record->setTimingPID(timing_pid, timing_pid_type);
        }
 }