[pvrparse, tstools] fix for 16x playback H.265.
[vuplus_dvbapp] / lib / dvb / tstools.cpp
old mode 100644 (file)
new mode 100755 (executable)
index 438f6d6..379df9b
@@ -7,7 +7,6 @@
 #include <stdio.h>
 
 eDVBTSTools::eDVBTSTools()
-       :m_file_lock(true)
 {
        m_pid = -1;
        m_maxrange = 256*1024;
@@ -23,19 +22,39 @@ eDVBTSTools::eDVBTSTools()
        m_futile = 0;
 }
 
+void eDVBTSTools::closeSource()
+{
+       m_source = NULL;
+}
+
 eDVBTSTools::~eDVBTSTools()
 {
-       closeFile();
+       closeSource();
 }
 
 int eDVBTSTools::openFile(const char *filename, int nostreaminfo)
 {
+       eRawFile *f = new eRawFile();
+       ePtr<iTsSource> src = f;
+
+       if (f->open(filename, 1) < 0)
+               return -1;
+
+       setSource(src, nostreaminfo ? NULL : filename);
+
+       return 0;
+}
+
+void eDVBTSTools::setSource(ePtr<iTsSource> &source, const char *stream_info_filename)
+{
        closeFile();
-       
-       if (!nostreaminfo)
+
+       m_source = source;
+
+       if (stream_info_filename)
        {
-               eDebug("loading streaminfo for %s", filename);
-               m_streaminfo.load(filename);
+               eDebug("loading streaminfo for %s", stream_info_filename);
+               m_streaminfo.load(stream_info_filename);
        }
        
        if (!m_streaminfo.empty())
@@ -45,19 +64,14 @@ int eDVBTSTools::openFile(const char *filename, int nostreaminfo)
 //             eDebug("no recorded stream information available");
                m_use_streaminfo = 0;
        }
-       
-       m_samples_taken = 0;
 
-       eSingleLocker l(m_file_lock);
-       if (m_file.open(filename, 1) < 0)
-               return -1;
-       return 0;
+       m_samples_taken = 0;
 }
 
 void eDVBTSTools::closeFile()
 {
-       eSingleLocker l(m_file_lock);
-       m_file.close();
+       if (m_source)
+               closeSource();
 }
 
 void eDVBTSTools::setSyncPID(int pid)
@@ -77,31 +91,24 @@ int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
                if (!m_streaminfo.getPTS(offset, pts))
                        return 0;
        
-       if (!m_file.valid())
+       if (!m_source || !m_source->valid())
                return -1;
 
        offset -= offset % 188;
 
-       eSingleLocker l(m_file_lock);
-       if (m_file.lseek(offset, SEEK_SET) < 0)
-       {
-               eDebug("lseek failed");
-               return -1;
-       }
-       
        int left = m_maxrange;
        
        while (left >= 188)
        {
                unsigned char packet[188];
-               if (m_file.read(packet, 188) != 188)
+               if (m_source->read(offset, packet, 188) != 188)
                {
                        eDebug("read error");
                        break;
                }
                left -= 188;
                offset += 188;
-               
+
                if (packet[0] != 0x47)
                {
                        eDebug("resync");
@@ -111,8 +118,8 @@ int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
                                if (packet[i] == 0x47)
                                        break;
                                ++i;
+                               --offset;
                        }
-                       offset = m_file.lseek(i - 188, SEEK_CUR);
                        continue;
                }
                
@@ -205,6 +212,8 @@ int eDVBTSTools::getPTS(off_t &offset, pts_t &pts, int fixed)
                                                        break;
                                                case 0x71: // AC3 / DTS
                                                        break;
+                                               case 0x72: // DTS - HD
+                                                       break;
                                                default:
                                                        eDebug("skip unknwn stream_id_extension %02x\n", payload[9+offs]);
                                                        continue;
@@ -404,7 +413,7 @@ int eDVBTSTools::getNextAccessPoint(pts_t &ts, const pts_t &start, int direction
 
 void eDVBTSTools::calcBegin()
 {
-       if (!m_file.valid())
+       if (!m_source || !m_source->valid())
                return;
 
        if (!(m_begin_valid || m_futile))
@@ -419,11 +428,10 @@ void eDVBTSTools::calcBegin()
 
 void eDVBTSTools::calcEnd()
 {
-       if (!m_file.valid())
+       if (!m_source || !m_source->valid())
                return;
 
-       eSingleLocker l(m_file_lock);
-       off_t end = m_file.lseek(0, SEEK_END);
+       off_t end = m_source->lseek(0, SEEK_END);
        
        if (llabs(end - m_last_filelength) > 1*1024*1024)
        {
@@ -573,31 +581,28 @@ int eDVBTSTools::takeSample(off_t off, pts_t &p)
 int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
 {
                /* FIXME: this will be factored out soon! */
-       if (!m_file.valid())
+       if (!m_source || !m_source->valid())
        {
                eDebug(" file not valid");
                return -1;
        }
 
-       eSingleLocker l(m_file_lock);
-       if (m_file.lseek(0, SEEK_SET) < 0)
-       {
-               eDebug("seek failed");
-               return -1;
-       }
+       off_t position=0;
 
        int left = 5*1024*1024;
        
        while (left >= 188)
        {
                unsigned char packet[188];
-               if (m_file.read(packet, 188) != 188)
+               int ret = m_source->read(position, packet, 188);
+               if (ret != 188)
                {
                        eDebug("read error");
                        break;
                }
                left -= 188;
-               
+               position += 188;
+
                if (packet[0] != 0x47)
                {
                        int i = 0;
@@ -605,12 +610,11 @@ int eDVBTSTools::findPMT(int &pmt_pid, int &service_id)
                        {
                                if (packet[i] == 0x47)
                                        break;
+                               --position;
                                ++i;
                        }
-                       m_file.lseek(i - 188, SEEK_CUR);
                        continue;
                }
-               
                int pid = ((packet[1] << 8) | packet[2]) & 0x1FFF;
                
                int pusi = !!(packet[1] & 0x40);
@@ -644,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)
        {
@@ -664,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;
@@ -677,10 +688,17 @@ 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_frame = ((data & 0xFF) == 0x0009) || ((data & 0xFF) == 0x00); /* H.264 UAD or MPEG2 start code */
+               int is_start = 0;
+               if ((data & 0xE0FF) == 0x0009) /* H.264 NAL unit access delimiter with I-frame*/
+                       is_start =1;
+               else if ((data & 0xE07E) == 0x0046) /* H.265 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 & 0x7E) == 0x0046) || ((data & 0xFF) == 0x00); /* H.264 UAD or H.265 UAD or MPEG2 start code */
                
                if (is_frame)
                {
@@ -689,7 +707,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;
 
@@ -698,6 +716,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
@@ -719,7 +738,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;
@@ -729,9 +748,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);
-       } while (((data & 0xFF) != 9) && ((data & 0xFF) != 0x00)); /* next frame */
+//             eDebug("%08llx@%llu (next frame)", data, offset);
+       } while (((data & 0xFF) != 9) && ((data & 0x7E) != 0x46) && ((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);
@@ -739,21 +782,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) {
@@ -767,7 +812,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;
@@ -775,7 +820,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)
                {
@@ -783,7 +828,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;
@@ -791,7 +836,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);