mirror of
https://projects.vdr-developer.org/git/vdr-plugin-streamdev.git
synced 2023-10-10 19:16:51 +02:00
88 lines
3.1 KiB
C
88 lines
3.1 KiB
C
#include "remux/tsremux.h"
|
|
|
|
#define SC_PICTURE 0x00 // "picture header"
|
|
#define PID_MASK_HI 0x1F
|
|
#define VIDEO_STREAM_S 0xE0
|
|
|
|
using namespace Streamdev;
|
|
|
|
void cTSRemux::SetBrokenLink(uchar *Data, int Length)
|
|
{
|
|
int PesPayloadOffset = 0;
|
|
if (AnalyzePesHeader(Data, Length, PesPayloadOffset) >= phMPEG1 && (Data[3] & 0xF0) == VIDEO_STREAM_S) {
|
|
for (int i = PesPayloadOffset; i < Length - 7; i++) {
|
|
if (Data[i] == 0 && Data[i + 1] == 0 && Data[i + 2] == 1 && Data[i + 3] == 0xB8) {
|
|
if (!(Data[i + 7] & 0x40)) // set flag only if GOP is not closed
|
|
Data[i + 7] |= 0x20;
|
|
return;
|
|
}
|
|
}
|
|
dsyslog("SetBrokenLink: no GOP header found in video packet");
|
|
}
|
|
else
|
|
dsyslog("SetBrokenLink: no video packet in frame");
|
|
}
|
|
|
|
int cTSRemux::GetPid(const uchar *Data)
|
|
{
|
|
return (((uint16_t)Data[0] & PID_MASK_HI) << 8) | (Data[1] & 0xFF);
|
|
}
|
|
|
|
int cTSRemux::GetPacketLength(const uchar *Data, int Count, int Offset)
|
|
{
|
|
// Returns the length of the packet starting at Offset, or -1 if Count is
|
|
// too small to contain the entire packet.
|
|
int Length = (Offset + 5 < Count) ? (Data[Offset + 4] << 8) + Data[Offset + 5] + 6 : -1;
|
|
if (Length > 0 && Offset + Length <= Count)
|
|
return Length;
|
|
return -1;
|
|
}
|
|
|
|
int cTSRemux::ScanVideoPacket(const uchar *Data, int Count, int Offset, uchar &PictureType)
|
|
{
|
|
// Scans the video packet starting at Offset and returns its length.
|
|
// If the return value is -1 the packet was not completely in the buffer.
|
|
int Length = GetPacketLength(Data, Count, Offset);
|
|
if (Length > 0) {
|
|
int PesPayloadOffset = 0;
|
|
if (AnalyzePesHeader(Data + Offset, Length, PesPayloadOffset) >= phMPEG1) {
|
|
const uchar *p = Data + Offset + PesPayloadOffset + 2;
|
|
const uchar *pLimit = Data + Offset + Length - 3;
|
|
#ifdef TEST_cVideoRepacker
|
|
// cVideoRepacker ensures that a new PES packet is started for a new sequence,
|
|
// group or picture which allows us to easily skip scanning through a huge
|
|
// amount of video data.
|
|
if (p < pLimit) {
|
|
if (p[-2] || p[-1] || p[0] != 0x01)
|
|
pLimit = 0; // skip scanning: packet doesn't start with 0x000001
|
|
else {
|
|
switch (p[1]) {
|
|
case SC_SEQUENCE:
|
|
case SC_GROUP:
|
|
case SC_PICTURE:
|
|
break;
|
|
default: // skip scanning: packet doesn't start a new sequence, group or picture
|
|
pLimit = 0;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
while (p < pLimit && (p = (const uchar *)memchr(p, 0x01, pLimit - p))) {
|
|
if (!p[-2] && !p[-1]) { // found 0x000001
|
|
switch (p[1]) {
|
|
case SC_PICTURE: PictureType = (p[3] >> 3) & 0x07;
|
|
return Length;
|
|
}
|
|
p += 4; // continue scanning after 0x01ssxxyy
|
|
}
|
|
else
|
|
p += 3; // continue scanning after 0x01xxyy
|
|
}
|
|
}
|
|
PictureType = NO_PICTURE;
|
|
return Length;
|
|
}
|
|
return -1;
|
|
}
|
|
|