#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)
{
}
eMPEGStreamInformation::~eMPEGStreamInformation()
{
+ readClose();
+ writeClose();
+}
+
+void eMPEGStreamInformation::readClose()
+{
if (m_structure_read)
+ {
fclose(m_structure_read);
+ m_structure_read = 0;
+ }
+}
+
+void eMPEGStreamInformation::writeClose()
+{
if (m_structure_write)
+ {
fclose(m_structure_write);
+ m_structure_write = 0;
+ }
}
int eMPEGStreamInformation::startSave(const char *filename)
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");
int eMPEGStreamInformation::load(const char *filename)
{
m_filename = filename;
- if (m_structure_read)
- fclose(m_structure_read);
+ readClose();
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];
return 0;
}
-bool eMPEGStreamInformation::empty()
-{
- return m_access_points.empty();
-}
-
void eMPEGStreamInformation::fixupDiscontinuties()
{
m_timestamp_deltas.clear();
pts_t current = i->second - currentDelta;
pts_t diff = current - lastpts_t;
- if (llabs(diff) > (90000*5)) // 5sec diff
+ if (llabs(diff) > (90000*10)) // 10sec diff
{
// eDebug("%llx < %llx, have discont. new timestamp is %llx (diff is %llx)!", current, lastpts_t, i->second, diff);
currentDelta = i->second - lastpts_t; /* FIXME: should be the extrapolated new timestamp, based on the current rate */
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)
+ if(update_structure_cache_entries(_offset))
{
- 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] = 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;
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;
+ 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))
+ {
+ return -1;
+ }
+ }
+
+ int i = 0;
+ while ((off_t)m_structure_cache[i * 2] <= offset)
+ {
+ ++i;
+ 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[(m_structure_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;
+ 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))
+ {
+ return -1;
+ }
+ }
+
+ int i = m_structure_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 == m_structure_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;
}
-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)
+int eMPEGStreamInformation::update_structure_cache_entries(off_t offset)
+{
+ 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];
+ 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_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_size, m_structure_read);
+ eDebug("%d entries", num);
+ for (i = 0; i < struture_cache_size; ++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_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),
+ m_enable_accesspoints(true)
{
}
if (!(pkt[3] & 0x10)) /* no payload? */
return 0;
+ if (pkt[3] & 0xc0)
+ {
+ /* scrambled stream, we cannot parse pts */
+ return 0;
+ }
+
if (pkt[3] & 0x20) // adaptation field present?
pkt += pkt[4] + 4 + 1; /* skip adaptation field and header */
else
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.")*/;
+ }
}
}
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 */
+ {
+ int nal_unit_type = (sc >> 1);
+ if (nal_unit_type == 35) /* H265 NAL unit access delimiter */
+ {
+ unsigned long long data = sc | (pkt[5] << 8);
+ m_streaminfo.writeStructureEntry(offset + pkt_offset, data);
+
+ if (m_enable_accesspoints)
+ {
+ if ((pkt[5] >> 5) == 0) /* check pic_type for I-frame */
+ {
+ if (ptsvalid)
+ {
+ m_streaminfo.m_access_points[offset] = pts;
+ }
+ }
+ }
}
}
}