Fix for ts playback 16x and rewind.(get sequence header before I-frame)
authorChang.H.S <jhs@dev3>
Tue, 30 Oct 2012 05:56:13 +0000 (14:56 +0900)
committerChang.H.S <jhs@dev3>
Tue, 30 Oct 2012 09:22:45 +0000 (18:22 +0900)
lib/dvb/dvb.cpp [changed mode: 0644->0755]
lib/dvb/pvrparse.cpp [changed mode: 0644->0755]
lib/dvb/pvrparse.h [changed mode: 0644->0755]
lib/dvb/tstools.cpp [changed mode: 0644->0755]
lib/dvb/tstools.h

old mode 100644 (file)
new mode 100755 (executable)
index ce09603..a1fe247
@@ -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;
old mode 100644 (file)
new mode 100755 (executable)
index e19dd1e..b1c8666
@@ -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)
 {
 }
old mode 100644 (file)
new mode 100755 (executable)
index 28c0314..fa931a3
@@ -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;
old mode 100644 (file)
new mode 100755 (executable)
index 6cd855c..2c0a17c
@@ -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);
 
index 9982792..9d66efc 100644 (file)
@@ -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;