ТС: Полное название — MPEG2-TS. TS — это аббревиатура «Транспортный поток». Он отправляется пакетами, каждый пакет имеет длину 188 байт (есть также пакеты по 192 и 204 байта). Структура пакета такова, заголовок — 4 байта (первый байт — 0x47), полезная нагрузка — 184 байта. В поток TS могут быть заполнены многие типы данных, такие как видео, аудио, пользовательская информация и т. д. MPEG2-TS в основном используется для передачи программ в реальном времени, например телепрограмм в реальном времени. Особенностью формата MPEG2-TS является то, что он требует независимого декодирования любого сегмента видеопотока. Проще говоря, отрезание первой части VOB-файла на DVD (или повреждение данных) приведет к тому, что весь файл невозможно будет декодировать, а телепрограммы можно будет декодировать (просматривать) в любой момент, когда Телевизор включен.
Для анализа TS см.: 2.4 Требования к битовому потоку транспортного потока стандарта ISO/IEC 13818-1.
Конкретные ссылки следующие:
https://www.iso.org/obp/ui/#iso:std:iso-iec:13818:-1:ed-7:v1:en
Структура пакета TS:
Описание информации в заголовке:
Подробности следующие:
- sync_byte: фиксированное значение 0100 0111 (0x47); этот байт распознается декодером и позволяет отделить заголовок и полезную нагрузку друг от друга.
Пример парсинга BAT:
TS-Пакет 1:
Эта сумка особенная. Почему ее называют первой? Потому что? continuity_counter=0 & payload_unit_start_indicator=1。
Другими словами, любой фильтр сегмента SCTION начинается с пакета TS с параметром Continuous_counter=0. В этом случае максимальный размер SECTION составляет 184X16=2944 байта.
Таким образом, размер SECTION зависит от синтаксиса SECTION, который будет анализироваться. Извлекая первые 3 байта полезной нагрузки, вы узнаете длину SCTION. Формула расчета обычно следующая:
secLen = ((uint16_t)(buf[1] & 0xf)) << 8 | buf[2]) buf — начальная позиция полезной нагрузки. Подробности смотрите в синтаксической структуре таблицы BAT.
Обзор следующий:
47 40 11 10 означает, что поле настройки отсутствует и имеется флаг начала единицы загрузки. Тогда начальная позиция полезной нагрузки находится после data[5], длина полезной нагрузки равна 183, а первые 3 байта полезной нагрузки — 4a f2 ed. . Текущая длина SCTION равна secLen=749 байт.
TS-Пакет 2:
47 00 11 11 означает, что нет поля настройки и нет флага начала единицы загрузки, тогда начальная позиция полезной нагрузки находится после data[4], а длина полезной нагрузки равна 184.
TS-Пакет 3:
47 00 11 12 означает отсутствие поля настройки и отсутствие флага начала единицы нагрузки, тогда начальная позиция полезной нагрузки находится после data[4], а длина полезной нагрузки равна 184.
TS-пакет 4:
47 00 11 13 означает отсутствие поля настройки и отсутствие флага начала единицы нагрузки, тогда начальная позиция полезной нагрузки находится после data[4], а длина полезной нагрузки равна 184.
TS-пакет 5:
47 00 11 14 означает отсутствие поля настройки и отсутствие флага начала единицы нагрузки, тогда начальная позиция полезной нагрузки находится после data[4], а длина полезной нагрузки равна 17.
Это последний пакет TS текущего SCTION, как определить, последний ли это пакет?
Во-первых, когда мы разобрали первый пакет TS, мы получили secLen=749. По мере увеличения инкремента пакетов мы последовательно получили полезную нагрузку 749-183-184-184-184=17, поэтому при анализе пятого пакета TS When, полезная нагрузка составляет 17 байт, BAT завершает работу по сбору данных, синтаксический анализ BAT выглядит следующим образом:
Поток TS должен содержать пакеты PAT, пакеты PMT, несколько аудиопакетов, несколько видеопакетов, несколько пакетов PCR и другие информационные пакеты.
Процесс анализа данных потока TS: найти пакет с PID 0x0, проанализировать PAT, program_map_PID в пакете PAT представляет PID поиска PMT, элементарный_PID в пакете PMT представляет PID аудио и; видеопакет и пакет PMT PCR_PID представляет собой PID PCR. Иногда PID PCR совпадает с PID аудио или видео, что означает, что PCR будет интегрирован в пакет аудио и видео. Иногда обратите внимание на анализ. PCR — это отдельный пакет CAT, NIT, SDT, а PID EIT: 0x01, 0x10, 0x11, 0x12.
Давайте проанализируем это ниже. В стандарте ISO/IEC 13818-1 указано, что значение PID BAT равно 0x11, а идентификатор пакета TS (т. е. sync_byte) — 0x47, чтобы гарантировать достоверность данных в этом пакете TS. , сначала ищем 47 40 11 Эти три группы шестнадцатеричных чисел, почему они такие? Конкретный секрет заключается в структуре пакета TS. Как упоминалось ранее, sync_byte имеет фиксированное значение 0x47. Теперь посмотрите на четыре элемента Transport_error_indicator, payload_unit_start_indicator, Transport_priority и PID. PID равен 0x11, что является идентификацией BAT. Transport_error_indicator равен 0, а Transport_priority равен 0. Думайте о них как о двух наборах восьмизначных шестнадцатеричных чисел: 40 11. Теперь посмотрим на наш пример фрагмента потока TS. Кажется, он начинается с 47 40 11. Заголовок потока TS занимает 4 байта. Содержимое оставшейся части нагрузки определяется PID. Примером является таблица BAT. Здесь есть кое-что, на что следует обратить внимание: когда payload_unit_start_indicator равен 1, после первых 4 байтов будет байт корректировки, и его значение определяет конкретную начальную позицию содержимого полезной нагрузки. Теперь посмотрим на данные в примере 47 40 11 10 00. Пятый байт — 00, а это значит, что сразу после 00 идет конкретное содержимое загрузки, то есть за 4a f2 ed следует загрузка.
До сих пор была поднята проблема обнаружения полезной нагрузки TS-пакетов. При обнаружении полезной нагрузки следует обратить внимание на два момента:
В качестве примера возьмем «tsBuf[]», в «tsBuf[]» хранится кадр пакета TS, tsBuf[0]=0x47, заголовок синхронизации TS, тогда tsBuf[4] — длина адаптивной области.
transport_packet(){
sync_byte
...
adaptation_field_control 2 bslbf
continuity_counter 4 uimsbf
if(adaptation_field_control == '10' || adaptation_field_control == '11'){
adaptation_field()
}
...
}
tsBuf[4]=adaptation_field_length
adaptation_field(){
adaptation_field_length 8 uimsbf
if(adaptation_field_length>0){
...
PCR_flag 1 bslbf
...
if(PCR_flag == '1'){
program_clock_reference_base 33 uimsbf
Reserved 6 bslbf
program_clock_reference_extension 9 uimsbf
...
}
}
}
Синтаксис ISO/IEC 13818-1 для адаптивных зон следующий:
Заголовок TS имеет 4 байта:
//Transport Stream header
typedef struct TS_header
{
unsigned sync_byte :8; //Байт синхронизации, фиксированный на 0x47 , указывая, что следующий пакет является TS. Конечно, 0x47 не появится в данных следующего пакета.
unsigned transport_error_indicator :1; //Бит флага ошибки передачи. Обычно в случае ошибки передачи пакет не будет обработан.
unsigned payload_unit_start_indicator :1; //Флаг начала полезной нагрузки имеет разные функции в зависимости от содержимого последующей полезной нагрузки.
// Когда payload_unit_start_indicator равен 1, после первых 4 байтов будет байт корректировки, и его номер определяет конкретную начальную позицию содержимого полезной нагрузки.
unsigned transport_priority :1; //Бит приоритета передачи, 1 указывает на высокий приоритет
unsigned PID :13; //Тип данных полезной нагрузки
unsigned transport_scrambling_control :2; //Флаг шифрования, 00 означает отсутствие шифрования
unsigned adaption_field_control :2; //Настройка управления полем. 01 содержит только полезную нагрузку, 10 содержит только поля настройки, а 11 содержит и поля настройки, и полезную нагрузку. Если это 00, декодер не будет его обрабатывать.
unsigned continuity_counter :4; //4-битный счетчик, диапазон 0-15
} TS_header;
//Описание специального параметра:
//sync_byte:0x47
//payload_unit_start_indicator: 0x01 указывает на наличие заголовка PSI или PES
//PID: 0x0 указывает, что последующим содержимым загрузки является PAT, а разные PID указывают на разные нагрузки.
//adaption_field_control:
// 0x0: // reserved for future use by ISO/IEC
// 0x1: // Никаких полей настройки, только полезная нагрузка
// 0x2: // Только поля настройки, без полезной нагрузки
// 0x3: // Содержит полезную нагрузку после настройки полей
// Parse TS header
int Parse_TS_header(unsigned char *pTSBuf, TS_header *pheader)
{
pheader->sync_byte = pTSBuf[0];
if (pheader->sync_byte != 0x47)
return -1;
pheader->transport_error_indicator = pTSBuf[1] >> 7;
pheader->payload_unit_start_indicator = pTSBuf[1] >> 6 & 0x01;
pheader->transport_priority = pTSBuf[1] >> 5 & 0x01;
pheader->PID = (pTSBuf[1] & 0x1F) << 8 | pTSBuf[2];
pheader->transport_scrambling_control = pTSBuf[3] >> 6;
pheader->adaption_field_control = pTSBuf[3] >> 4 & 0x03;
pheader->continuity_counter = pTSBuf[3] & 0x0F;
return 0;
}
Для анализа заголовка пакета TS см.: 2.4.3.2 Уровень пакета транспортного потока ISO/IEC 13818-1.
Значение PID в заголовке TS_header равно 0x0, что указывает на то, что текущей загрузкой является PAT (таблица ассоциаций программ). Информацию данных PAT можно понимать как информацию о программе, содержащуюся во всем потоке TS.
// Program Association Table
typedef struct PAT_Packet_tag
{
unsigned table_id : 8; //Фиксировано на 0x00 , флаг означает, что таблица является PAT
unsigned section_syntax_indicator : 1; //Флаг синтаксиса сегмента, фиксированный на 1
unsigned zero : 1; //0
unsigned reserved_1 : 2; // Зарезервированный бит
unsigned section_length : 12 //Указывает количество полезных байтов, следующих за этим байтом, включая CRC32;
unsigned transport_stream_id : 16; //Идентификатор этого транспортного потока отличается от других мультиплексированных потоков в сети.
unsigned reserved_2 : 2; // Зарезервированный бит
unsigned version_number : 5; //Диапазон 0-31, указывающий номер версии PAT
unsigned current_next_indicator : 1; //Является ли отправленный PAT действительным в данный момент или действительным следующий PAT?
unsigned section_number : 8; //Номер сегмента. PAT может быть разделен на несколько сегментов для передачи. Первый сегмент равен 00, а каждый последующий сегмент увеличивается на 1. Всего может быть до 256 сегментов.
unsigned last_section_number : 8; //Номер последнего сегмента
// for(i=0; i<N; i++)
// {
unsigned program_number : 16;
unsigned reserved_3 : 3;
unsigned network_PID : 16; // Или program_map_PID
unsigned CRC_32 : 32;
// }
} PAT_Packet;
// Parse PAT
int Parse_PAT(unsigned char *pTSBuf, PAT_Packet *packet)
{
TS_header TSheader;
if (Parse_TS_packet_header(pTSBuf, &TSheader) != 0)
return -1;
if (TSheader.payload_unit_start_indicator == 0x01) // Указывает, что он содержит заголовок PSI или PES.
{
if (TSheader.PID == 0x0) // означает ПАТ
{
int iBeginlen = 4;
int adaptation_field_length = pTSBuf[4];
switch(TSheader.adaption_field_control)
{
case 0x0: // reserved for future use by ISO/IEC
return -1;
case 0x1: // Никаких полей настройки, только полезная нагрузка
iBeginlen += pTSBuf[iBeginlen] + 1; // + pointer_field
break;
case 0x2: // Только поля настройки, без полезной нагрузки
return -1;
case 0x3: // Содержит полезную нагрузку после настройки полей
if (adaptation_field_length > 0)
{
iBeginlen += 1; // адаптация_field_length занимает 8 бит
iBeginlen += adaptation_field_length; // + adaptation_field_length
}
else
{
iBeginlen += 1; // адаптация_field_length занимает 8 бит
}
iBeginlen += pTSBuf[iBeginlen] + 1; // + pointer_field
break;
default:
break;
}
unsigned char *pPAT = pTSBuf + iBeginlen;
packet->table_id = pTSBuf[0];
packet->section_syntax_indicator = pTSBuf[1] >> 7;
packet->zero = pTSBuf[1] >> 6 & 0x1;
packet->reserved_1 = pTSBuf[1] >> 4 & 0x3;
packet->section_length = (pTSBuf[1] & 0x0F) << 8 | pTSBuf[2];
packet->transport_stream_id = pTSBuf[3] << 8 | pTSBuf[4];
packet->reserved_2 = pTSBuf[5] >> 6;
packet->version_number = pTSBuf[5] >> 1 & 0x1F;
packet->current_next_indicator = (pTSBuf[5] << 7) >> 7;
packet->section_number = pTSBuf[6];
packet->last_section_number = pTSBuf[7];
int len = 0;
len = 3 + packet->section_length;
packet->CRC_32 = (pTSBuf[len-4] & 0x000000FF) << 24
| (pTSBuf[len-3] & 0x000000FF) << 16
| (pTSBuf[len-2] & 0x000000FF) << 8
| (pTSBuf[len-1] & 0x000000FF);
int n = 0;
for ( n = 0; n < (packet->section_length - 12); n += 4 )
{
packet->program_number = pTSBuf[8 + n ] << 8 | pTSBuf[9 + n ];
packet->reserved_3 = pTSBuf[10 + n ] >> 5;
if ( packet->program_number == 0x00)
{
packet->network_PID = (pTSBuf[10 + n ] & 0x1F) << 8 | pTSBuf[11 + n ];
}
else
{
// Действительный PID PMT, а затем используйте этот PIDценить, чтобы найти пакет PMT.
program_map_PID = (pTSBuf[10 + n] & 0x1F) << 8 | pTSBuf[11 + n];
}
}
return 0;
}
}
return -1;
}
Для анализа данных PAT см.: 2.4.4.3 Таблица ассоциаций программ ISO/IEC 13818-1.
PID PMT (таблицы сопоставления программ) можно определить из program_map_PID в пакете PAT. Информацию данных PMT можно понимать как аудио- и видеоинформацию, содержащуюся в этой программе.
// Program Map Table
typedef struct PMT_Packet_tag
{
unsigned table_id : 8;
unsigned section_syntax_indicator : 1;
unsigned zero : 1;
unsigned reserved_1 : 2;
unsigned section_length : 12;
unsigned program_number : 16;
unsigned reserved_2 : 2;
unsigned version_number : 5;
unsigned current_next_indicator : 1;
unsigned section_number : 8;
unsigned last_section_number : 8;
unsigned reserved_3 : 3;
unsigned PCR_PID : 13;
unsigned reserved_4 : 4;
unsigned program_info_length : 12;
// for(i=0; i<N; i++)
// {
unsigned stream_type : 8;
unsigned reserved_5 : 3;
unsigned elementary_PID : 13;
unsigned reserved_6 : 4;
unsigned ES_info_length : 12;
// }
unsigned CRC_32 : 32;
} PMT_Packet;
// Parse PMT
int Parse_PMT(unsigned char *pTSBuf, PMT_Packet *packet)
{
// Просто обратитесь к Parse_PAT(), чтобы сделать это.
// ...
return 0;
}
Для анализа данных PMT см.: 2.4.4.8 Таблица карты программы ISO/IEC 13818-1.
Согласно документу, обратитесь к процессу анализа PAT и PMT, чтобы завершить анализ PES.
Что необходимо отметить, так это анализ PTS в PES. Вообще говоря, при 90 к Гц значение PTS/9000 находится в секундах.
unsigned long long Parse_PTS(unsigned *pBuf)
{
unsigned long long llpts = (((unsigned long long)(pBuf[0] & 0x0E)) << 29)
| (unsigned long long)(pBuf[1] << 22)
| (((unsigned long long)(pBuf[2] & 0xFE)) << 14)
| (unsigned long long)(pBuf[3] << 7)
| (unsigned long long)(pBuf[4] >> 1);
return llpts;
}
Для анализа данных PES требуется ссылка: 2.5.5.1 Синтаксис синтаксиса пакета PES для каталога программного потока.
Ссылка на статью: https://www.cnblogs.com/jiangzhaowei/p/4344886.html.