From: Chang.H.S Date: Tue, 30 Oct 2012 05:56:13 +0000 (+0900) Subject: Fix for ts playback 16x and rewind.(get sequence header before I-frame) X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=commitdiff_plain;h=11a55c0debe7dcb8a336eb5e59655d8c87778175 Fix for ts playback 16x and rewind.(get sequence header before I-frame) --- diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp old mode 100644 new mode 100755 index ce09603..a1fe247 --- a/lib/dvb/dvb.cpp +++ b/lib/dvb/dvb.cpp @@ -1352,8 +1352,9 @@ static inline long long align_with_len(long long x, int align, size_t &len) if (sign) x = -x; - x -= x % align; - len += x % align; + int r = x % align; + x -= r; + len += r; if (sign) x = -x; @@ -1382,13 +1383,13 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off max = align(m_skipmode_n, blocksize); } - eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m); + eDebug("getNextSourceSpan, current offset is %08lld, m_skipmode_m = %d!", current_offset, m_skipmode_m); int frame_skip_success = 0; if (m_skipmode_m) { int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder; - eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder); + eDebug("we are at %lld, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder); size_t iframe_len; off_t iframe_start = current_offset; int frames_skipped = frames_to_skip; @@ -1409,20 +1410,24 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off if (!frame_skip_success) { current_offset += align(m_skipmode_m, blocksize); - - if (m_skipmode_m) + if(current_offset < 0) + current_offset = 0; + else { - eDebug("we are at %llx, and we try to find the iframe here:", current_offset); - size_t iframe_len; - off_t iframe_start = current_offset; - - int direction = (m_skipmode_m < 0) ? -1 : +1; - if (m_tstools.findFrame(iframe_start, iframe_len, direction)) - eDebug("failed"); - else + if (m_skipmode_m) { - current_offset = align_with_len(iframe_start, blocksize, iframe_len); - max = align(iframe_len, blocksize); + eDebug("we are at %lld, and we try to find the iframe here:", current_offset); + size_t iframe_len; + off_t start_offset = current_offset; + off_t new_offset = start_offset; + int direction = (m_skipmode_m < 0) ? -1 : +1; + if (m_tstools.findFrame(start_offset, new_offset, iframe_len, direction)) + eDebug("failed"); + else + { + current_offset = align_with_len(new_offset, blocksize, iframe_len); + max = align(iframe_len, blocksize); + } } } } @@ -1580,18 +1585,19 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off } } + if(current_offset <0) + current_offset =0; if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0)) { eDebug("reached SOF"); m_skipmode_m = 0; m_pvr_thread->sendEvent(eFilePushThread::evtUser); } - if (m_source_span.empty()) { start = current_offset; size = max; - eDebug("NO CUESHEET. (%08llx, %zd)", start, size); + eDebug("NO CUESHEET. (%08lld, %zd)", start, size); } else { start = current_offset; diff --git a/lib/dvb/pvrparse.cpp b/lib/dvb/pvrparse.cpp old mode 100644 new mode 100755 index e19dd1e..b1c8666 --- a/lib/dvb/pvrparse.cpp +++ b/lib/dvb/pvrparse.cpp @@ -421,12 +421,153 @@ int eMPEGStreamInformation::getStructureEntry(off_t &offset, unsigned long long if (!get_next) --i; -// eDebug("[%d] looked for %llx, found %llx=%llx", sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]); +// eDebug("[%d] looked for %lld, found %llu=%llx", sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]); offset = m_structure_cache[i * 2]; data = m_structure_cache[i * 2 + 1]; return 0; } +int eMPEGStreamInformation::getStructureEntry_next(off_t &offset, unsigned long long &data) +{ + if (!m_structure_read) + { + eDebug("getStructureEntry failed because of no m_structure_read"); + return -1; + } + + 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(update_structure_cache_entries(_offset)) + { + return -1; + } + } + + int i = 0; + while ((off_t)m_structure_cache[i * 2] <= offset) + { + ++i; + if (i == struture_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]); + return -1; + } + } + if (!i) + { + eDebug("structure data (first entry) consistency fail!"); + return -1; + } + +// eDebug("[%d] looked for %llu, found data %llu=%llx",sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]); + offset = m_structure_cache[i * 2]; + data = m_structure_cache[i * 2 + 1]; + return 0; +} + +int eMPEGStreamInformation::getStructureEntry_prev(off_t &offset, unsigned long long &data) +{ + if (!m_structure_read) + { + eDebug("getStructureEntry failed because of no m_structure_read"); + return -1; + } + + 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(update_structure_cache_entries(_offset)) + { + return -1; + } + } + + int i = struture_cache_entries-1; + while ((off_t)m_structure_cache[i * 2] >= offset) + { + if (i <= 0) + { + eDebug("structure data consistency fail!, we are looking for %llu, but last entry is %llu", offset, m_structure_cache[i * 2]); + return -1; + } + --i; + } + if (i == struture_cache_entries-1) + { + eDebug("structure data (first entry) consistency fail!"); + return -1; + } + +// eDebug("[%d] looked for %llu, found data %llu=%llx",sizeof offset, offset, m_structure_cache[i * 2], m_structure_cache[i * 2 + 1]); + offset = m_structure_cache[i * 2]; + data = m_structure_cache[i * 2 + 1]; + return 0; +} + +int eMPEGStreamInformation::update_structure_cache_entries(off_t offset) +{ + const int struture_cache_entries = sizeof(m_structure_cache) / 16; + 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 (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] = 0x7fffffffffffffffULL; + } + } + m_structure_cache_valid = 1; + 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) { } diff --git a/lib/dvb/pvrparse.h b/lib/dvb/pvrparse.h old mode 100644 new mode 100755 index 28c0314..fa931a3 --- a/lib/dvb/pvrparse.h +++ b/lib/dvb/pvrparse.h @@ -61,6 +61,9 @@ public: optionall, return next element. Offset will be returned. this allows you to easily get previous and next structure elements. */ int getStructureEntry(off_t &offset, unsigned long long &data, int get_next); + int getStructureEntry_next(off_t &offset, unsigned long long &data); + int getStructureEntry_prev(off_t &offset, unsigned long long &data); + int update_structure_cache_entries(off_t offset); std::string m_filename; int m_structure_cache_valid; diff --git a/lib/dvb/tstools.cpp b/lib/dvb/tstools.cpp old mode 100644 new mode 100755 index 6cd855c..2c0a17c --- a/lib/dvb/tstools.cpp +++ b/lib/dvb/tstools.cpp @@ -648,11 +648,12 @@ int eDVBTSTools::findPMT(int &pmt_pid, int &service_id) return -1; } -int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int frame_types) +int eDVBTSTools::findFrame(off_t &_iframe_offset, off_t &_new_offset, size_t &len, int &direction, int frame_types) { - off_t offset = _offset; + off_t offset = _iframe_offset; int nr_frames = 0; -// eDebug("trying to find iFrame at %llx", offset); + int is_mpeg = 0; +// eDebug("trying to find iFrame at %lld", offset); if (!m_use_streaminfo) { @@ -668,7 +669,13 @@ int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int fram while (1) { - if (m_streaminfo.getStructureEntry(offset, data, (direction == 0) ? 1 : 0)) + int res = -1; + if(direction<0) + res = m_streaminfo.getStructureEntry_prev(offset, data); + else + res = m_streaminfo.getStructureEntry_next(offset, data); + + if (res) { eDebug("getting structure info for origin offset failed."); return -1; @@ -681,9 +688,14 @@ int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int fram /* data is usually the start code in the lower 8 bit, and the next byte <<8. we extract the picture type from there */ /* we know that we aren't recording startcode 0x09 for mpeg2, so this is safe */ /* TODO: check frame_types */ - int is_start = (data & 0xE0FF) == 0x0009; /* H.264 NAL unit access delimiter with I-frame*/ - is_start |= (data & 0x3800FF) == 0x080000; /* MPEG2 picture start code with I-frame */ - + int is_start = 0; + if ((data & 0xE0FF) == 0x0009) /* H.264 NAL unit access delimiter with I-frame*/ + is_start =1; + else if((data & 0x3800FF) == 0x080000) /* MPEG2 picture start code with I-frame */ + { + is_start =1; + is_mpeg =1; + } int is_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */ if (is_frame) @@ -693,7 +705,7 @@ int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int fram else ++nr_frames; } -// eDebug("%08llx@%llx -> %d, %d", data, offset, is_start, nr_frames); +// eDebug("%08llx@%llu -> %d, %d (I-frame)", data, offset, is_start, nr_frames); if (is_start) break; @@ -702,6 +714,7 @@ int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int fram else if (direction == +1) direction = 0; } + off_t iframe_start = offset; off_t start = offset; #if 0 @@ -723,7 +736,7 @@ int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int fram /* let's find the next frame after the given offset */ do { - if (m_streaminfo.getStructureEntry(offset, data, 1)) + if (m_streaminfo.getStructureEntry_next(offset, data)) { eDebug("get next failed"); return -1; @@ -733,9 +746,33 @@ int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int fram eDebug("reached eof (while looking for end of iframe)"); return -1; } -// eDebug("%08llx@%llx (next)", data, offset); +// eDebug("%08llx@%llu (next frame)", data, offset); } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */ + if (is_mpeg) //MPEG2 picture start code with I-frame + { + off_t sequence_offset = start; + unsigned long long sequence_data; + int is_sequence =0; + int frame_length = (nr_frames<0) ? -nr_frames: nr_frames; + while(frame_length) + { +// --start; + if (m_streaminfo.getStructureEntry_prev(sequence_offset, sequence_data)) + { + eDebug("get previous failed"); + return -1; + } + if ((sequence_data & 0xFF) == 0xB3) /* sequence start or previous frame */ + is_sequence = 1; + if(((sequence_data & 0xFF) == 0x0009) || ((sequence_data & 0xFF) == 0x00)) /* H.264 UAD or MPEG2 start code */ + --frame_length; +// eDebug("[findFrame] %08llx@%llu -> %d, %d (sequence)", sequence_data, sequence_offset, is_sequence, frame_length); + if(is_sequence) /* get sequence frame */ + break; + } + start = sequence_offset; + } #if 0 /* align to TS pkt start */ start = start - (start % 188); @@ -743,21 +780,23 @@ int eDVBTSTools::findFrame(off_t &_offset, size_t &len, int &direction, int fram #endif len = offset - start; - _offset = start; + _new_offset = start; + _iframe_offset = iframe_start; direction = nr_frames; -// eDebug("result: offset=%llx, len: %ld", offset, (int)len); +// eDebug("result: start=%lld, iframe= %lld, next=%lld, len: %ld",start, iframe_start ,offset, (long int)len); return 0; } int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types) { int nr_frames, direction; -// eDebug("trying to move %d frames at %llx", distance, offset); +// eDebug("trying to move %d frames at %llu", distance, offset); frame_types = frametypeI; /* TODO: intelligent "allow IP frames when not crossing an I-Frame */ off_t new_offset = offset; size_t new_len = len; + off_t iframe_offset = new_offset; int first = 1; if (distance > 0) { @@ -771,7 +810,7 @@ int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int while (distance > 0) { int dir = direction; - if (findFrame(new_offset, new_len, dir, frame_types)) + if (findFrame(iframe_offset, new_offset, new_len, dir, frame_types)) { // eDebug("findFrame failed!\n"); return -1; @@ -779,7 +818,7 @@ int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int distance -= abs(dir); -// eDebug("we moved %d, %d to go frames (now at %llx)", dir, distance, new_offset); +// eDebug("we moved %d, %d to go frames (now at %llu)", dir, distance, new_offset); if (distance >= 0 || direction == 0) { @@ -787,7 +826,7 @@ int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int offset = new_offset; len = new_len; nr_frames += abs(dir); - } + } else if (first) { first = 0; offset = new_offset; @@ -795,7 +834,6 @@ int eDVBTSTools::findNextPicture(off_t &offset, size_t &len, int &distance, int nr_frames += abs(dir) + distance; // never jump forward during rewind } } - distance = (direction < 0) ? -nr_frames : nr_frames; // eDebug("in total, we moved %d frames", nr_frames); diff --git a/lib/dvb/tstools.h b/lib/dvb/tstools.h index 9982792..9d66efc 100644 --- a/lib/dvb/tstools.h +++ b/lib/dvb/tstools.h @@ -74,7 +74,7 @@ public: return values are the new offset, the length of the found frame (both unaligned), and the (signed) number of frames skipped. */ - int findFrame(off_t &offset, size_t &len, int &direction, int frame_types = frametypeI); + int findFrame(off_t &_iframe_offset, off_t &offset, size_t &len, int &direction, int frame_types = frametypeI); int findNextPicture(off_t &offset, size_t &len, int &distance, int frame_types = frametypeAll); private: int m_pid;