diff options
author | hschang <chang@dev3> | 2015-12-08 06:33:16 (GMT) |
---|---|---|
committer | hschang <chang@dev3> | 2015-12-08 06:33:16 (GMT) |
commit | e4ba778cdbf810d617153209c0e60196dddc3dbb (patch) | |
tree | 77f0eae0f66fddd4d286421c91af490f911cbc48 | |
parent | 283109fd71a9d1014a85d4ff92d17897943111ee (diff) |
[Timeshift] write .sc file during timeshift to improve rewind/fastforward(16x)
-rw-r--r-- | lib/dvb/demux.cpp | 12 | ||||
-rw-r--r-- | lib/dvb/demux.h | 1 | ||||
-rw-r--r-- | lib/dvb/idemux.h | 1 | ||||
-rwxr-xr-x | lib/dvb/pvrparse.cpp | 156 | ||||
-rwxr-xr-x | lib/dvb/pvrparse.h | 10 | ||||
-rwxr-xr-x | lib/dvb/tstools.cpp | 4 | ||||
-rwxr-xr-x | lib/service/servicedvb.cpp | 32 |
7 files changed, 111 insertions, 105 deletions
diff --git a/lib/dvb/demux.cpp b/lib/dvb/demux.cpp index f4d8618..0d03927 100644 --- a/lib/dvb/demux.cpp +++ b/lib/dvb/demux.cpp @@ -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 ¤t_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 diff --git a/lib/dvb/demux.h b/lib/dvb/demux.h index e73982e..ca7fc4d 100644 --- a/lib/dvb/demux.h +++ b/lib/dvb/demux.h @@ -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(); diff --git a/lib/dvb/idemux.h b/lib/dvb/idemux.h index 86b35fd..0cb82cf 100644 --- a/lib/dvb/idemux.h +++ b/lib/dvb/idemux.h @@ -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; diff --git a/lib/dvb/pvrparse.cpp b/lib/dvb/pvrparse.cpp index c5a5c9c..173a774 100755 --- a/lib/dvb/pvrparse.cpp +++ b/lib/dvb/pvrparse.cpp @@ -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; + } } } } diff --git a/lib/dvb/pvrparse.h b/lib/dvb/pvrparse.h index fa931a3..a15bbaf 100755 --- a/lib/dvb/pvrparse.h +++ b/lib/dvb/pvrparse.h @@ -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 diff --git a/lib/dvb/tstools.cpp b/lib/dvb/tstools.cpp index 379df9b..aefc3b5 100755 --- a/lib/dvb/tstools.cpp +++ b/lib/dvb/tstools.cpp @@ -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; diff --git a/lib/service/servicedvb.cpp b/lib/service/servicedvb.cpp index 7005c84..d3c6032 100755 --- a/lib/service/servicedvb.cpp +++ b/lib/service/servicedvb.cpp @@ -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); } } |