MPEG TS Как собрать секцию EIT
С целью разобраться со стандартом Mpeg Ts пишу собственную библиотеку для парсинга ts файлов на C#. Сделал и протестировал для таблиц PAT, CAT, PMT, NIT, SDT, BAT и для кучи дескрипторов. И для части EIT. Но попался мне один нестандартный поток в котором pointer_field (ISO/IEC 13818-1 п.п 2.4.4.1) не равен нулю. EIT поток с транспондера №27 спутника Eutelsat 36B. Стандарт такое допускает, но алгоритмов в которое это поддерживают я так и не нашёл. Собственно загвоздка вот в чем: Ранее (когда Pointer_field = 0) я находил значение section_length, создавал массив длинной section_length нужной мне таблицы и если это значение больше 184 байт ставил флаг, что таблица собрана не вся. Ждал следующую таблицу с этим же пидом и добавлял остаток в конец массива. Если же pointer_field !=0 , то бывает что смещение равно 179 байтам и само по себе значение section_length находиться в другой таблице. В этом месте у меня и получился затык. Может кто-то работает с библиотеками для парсинга mpeg ts, подскажите как собрать секцию EIT в таком случае. Ps потоки выложить могу.
Вот пример таблицы со смещением:

Здесь 0xB0 смещение относительно начала payload.
Ответы (1 шт):
Если кто-то будет интересоваться, то черновой, но зато рабочий вариант сбора таблицы у меня получился следующим:
internal void AddRawData(TsPacket tsPacket)
{
if (tsPacket.Payload_unit_start_indicator)
{
Pointer = tsPacket.Payload[0];
if (Pointer > 184) // 184 - длина пакета
{
throw new Exception($"Pointer field greater than packet length for pid: {tsPacket.Pid}");
}
if (isInProgresTable)
{
if (TableBytes < 3) // если таблица не завершена и мы ещё не можем вытащить длину секции, то обрабатываем этот случай здесь.
{
Buffer.BlockCopy(tsPacket.Payload, 1, tempBuffer, TableBytes, 3 - TableBytes);
CurrentTableSectionLength = (((tempBuffer[1] & 0x0F) << 8) + tempBuffer[2]);
if (CurrentTableSectionLength > Pointer)
{
throw new Exception(" section length greater than pointer!");
}
TableData = new byte[CurrentTableSectionLength + 3];
Buffer.BlockCopy(tempBuffer, 0, TableData, 0, 3);
var offsetInPayload = 1 + 3 - TableBytes; // 1 байт сам Pointer, 3 - TableBytes это сколько байт мы считали из предыдущего пакета.
var bytesToCopyCount = Pointer - (3 - TableBytes); // сколько нужно скопировать байт.
Buffer.BlockCopy(tsPacket.Payload, offsetInPayload, TableData, 3, bytesToCopyCount);
// table ready
isInProgresTable = false;
return;
}
else // если длина известна, но конец текущей таблицы находиться перед заголовком следующей, то это случай обрабатываем здесь.
{
Buffer.BlockCopy(tsPacket.Payload, 1, TableData, TableBytes, Pointer);
TableBytes += Pointer;
//table ready
isInProgresTable = false;
return;
}
}
isInProgresTable = true;
CurrentTablePointerField = Pointer;
if (Pointer >= 181) // если заголовок таблицы располагается в самом конце payload, причём таким образом, что нельзя сразу считать длину секции, то копируем 1 или 2 байта ( если 3. то уже можно считать длину) во временный буфер.
{
TableBytes = 184 - Pointer - 1;
tempBuffer = new byte[3];
Buffer.BlockCopy(tsPacket.Payload, Pointer + 1, tempBuffer, 0, TableBytes);
return;
}
else // здесь обрабатываем случай, когда длину можно считать сразу
{
CurrentTableSectionLength = (((tsPacket.Payload[Pointer + 2] & 0x0F) << 8) + tsPacket.Payload[Pointer + 3]);
TableData = new byte[CurrentTableSectionLength + 3];
if(CurrentTableSectionLength + 3 < 184 - Pointer)// здесь случай когда длина секции не превышает длину payload. Иными словами вся таблица здесь.
{
Buffer.BlockCopy(tsPacket.Payload, Pointer + 1, TableData, 0, TableData.Length);
// table ready
isInProgresTable = false;
return;
}
else // если таблица большая, то копируем данные и ждём следующих входных данных.
{
Buffer.BlockCopy(tsPacket.Payload, Pointer + 1, TableData, 0, 184 - Pointer - 1);
TableBytes = 184 - Pointer - 1;
return;
}
}
}
if (isInProgresTable) // если следующий пакет не имеет флага Payload start indicator, то нужно опять же рассмотреть несколько вариантов
{
if (TableBytes < 3) // если начало таблицы было в самом конце payload предыдущего пакета и мы не смогли сразу узнать длину секции
{
Buffer.BlockCopy(tsPacket.Payload, 0, tempBuffer, TableBytes, 3 - TableBytes);
CurrentTableSectionLength = (((tempBuffer[1] & 0x0F) << 8) + tempBuffer[2]);
TableData = new byte[CurrentTableSectionLength + 3];
if(CurrentTableSectionLength + 3 <= 184) // проверяем заканчивается ли таблица в этом пакета и если да, то обрабатываем этот случай тут
{
Buffer.BlockCopy(tempBuffer, 0, TableData, 0, 3);
CurrentTableSectionLength = 3;
Buffer.BlockCopy(tsPacket.Payload, 0, TableData, 3, CurrentTableSectionLength);
TableBytes = CurrentTableSectionLength + 3;
// table ready TableBytes = CurrentTableSectionLength + 3;
isInProgresTable = false;
return;
}
else // таблица большая и конец не в этом пакете.
{
Buffer.BlockCopy(tempBuffer, 0, TableData, 0, 3);
Buffer.BlockCopy(tsPacket.Payload, 3 - TableBytes, TableData, 3, 184 - (3 - TableBytes));
TableBytes += 184;
return;
}
}
else if(CurrentTableSectionLength + 3 - TableBytes < 184) // если пришла таблица с заранее известной длиной, то проверяем заканчивается ли она в этом пакете, если да, то обрабатываем это здесь
{
Buffer.BlockCopy(tsPacket.Payload, 0, TableData, TableBytes, CurrentTableSectionLength + 3 - TableBytes);
TableBytes = CurrentTableSectionLength + 3;
//table ready
isInProgresTable = false;
return;
}
else // если таблица пришла с заранее известной длиной, но конец не в этом пакете.
{
Buffer.BlockCopy(tsPacket.Payload, 0, TableData, TableBytes, 184);
TableBytes += 184;
return;
}
}
else
{
return;
}
}
В итоге полная таблица будет в массиве TableData, TableBytes - это количество байт которые мы считали из пакетов. tempBuffer - массив длинной 3 байта для хранения данных, чтобы можно было извлечь длину секции.