📄 mpeg2_transport.c
字号:
#include "mpeg4ip.h"
#include "mpeg2_transport.h"
#include <assert.h>
#include "mpeg2t_private.h"
#define DEBUG 1
#ifdef DEBUG
#define CHECK_MP2T_HEADER assert(*pHdr == MPEG2T_SYNC_BYTE)
#else
#define CHECK_MP2T_HEADER
#endif
uint32_t mpeg2t_find_sync_byte (const uint8_t *buffer, uint32_t buflen)
{
uint32_t offset;
offset = 0;
while (offset < buflen) {
if (buffer[offset] == MPEG2T_SYNC_BYTE) {
return (offset);
}
offset++;
}
return (offset);
}
uint32_t mpeg2t_transport_error_indicator (const uint8_t *pHdr)
{
CHECK_MP2T_HEADER;
return ((pHdr[1] >> 7) & 0x1);
}
uint32_t mpeg2t_payload_unit_start_indicator (const uint8_t *pHdr)
{
CHECK_MP2T_HEADER;
return ((pHdr[1] >> 6) & 0x1);
}
uint16_t mpeg2t_pid (const uint8_t *pHdr)
{
int pid;
CHECK_MP2T_HEADER;
pid = (pHdr[1] & 0x1f) << 8;
pid |= pHdr[2];
return (pid);
}
uint32_t mpeg2t_adaptation_control (const uint8_t *pHdr)
{
CHECK_MP2T_HEADER;
return ((pHdr[3] >> 4) & 0x3);
}
uint32_t mpeg2t_continuity_counter (const uint8_t *pHdr)
{
CHECK_MP2T_HEADER;
return (pHdr[3] & 0xf);
}
const uint8_t *mpeg2t_transport_payload_start (const uint8_t *pHdr,
uint32_t *payload_len)
{
uint32_t adaption_control;
CHECK_MP2T_HEADER;
if (mpeg2t_transport_error_indicator(pHdr) != 0) {
*payload_len = 0;
return NULL;
}
adaption_control = mpeg2t_adaptation_control(pHdr);
if (adaption_control == 1) {
*payload_len = 184;
return pHdr + 4;
}
if (adaption_control == 3) {
if (pHdr[4] > 183) {
*payload_len = 0;
return NULL;
}
*payload_len = 183 - pHdr[4];
return pHdr + 5 + pHdr[4];
}
*payload_len = 0;
return NULL;
}
static void mpeg2t_start_join_pak (mpeg2t_pid_t *pidptr,
const uint8_t *bufstart,
uint32_t buflen,
uint32_t seqlen,
uint32_t cc)
{
if (seqlen == 0) {
if (pidptr->data_len_max < buflen) {
pidptr->data = (uint8_t *)realloc(pidptr->data, buflen + 4096);
if (pidptr->data == NULL) {
pidptr->data_len_max = 0;
return;
}
pidptr->data_len_max = buflen + 4096;
}
} else if (seqlen > pidptr->data_len_max) {
pidptr->data = (uint8_t *)realloc(pidptr->data, seqlen);
if (pidptr->data == NULL) {
pidptr->data_len_max = 0;
return;
}
pidptr->data_len_max = seqlen;
}
pidptr->data_len = seqlen;
pidptr->data_len_loaded = buflen;
memcpy(pidptr->data, bufstart, buflen);
pidptr->lastcc = cc;
}
static int mpeg2t_join_pak (mpeg2t_pid_t *pidptr,
const uint8_t *bufstart,
uint32_t buflen,
uint32_t cc)
{
uint32_t nextcc;
uint32_t remaining;
if (pidptr->data_len_loaded == 0) {
mpeg2t_message(LOG_WARNING,
"Trying to add to unstarted packet - PID %x",
pidptr->pid);
return -1;
}
nextcc = (pidptr->lastcc + 1) & 0xf;
if (nextcc != cc) {
mpeg2t_message(LOG_ERR, "Illegal cc value %d - should be %d - PID %x",
cc, nextcc, pidptr->pid);
pidptr->data_len_loaded = 0;
return -1;
}
pidptr->lastcc = cc;
if (pidptr->data_len == 0) {
remaining = pidptr->data_len_max - pidptr->data_len_loaded;
if (remaining < buflen) {
pidptr->data = (uint8_t *)realloc(pidptr->data,
pidptr->data_len_max + 4096);
if (pidptr->data == NULL) {
pidptr->data_len_max = 0;
return -1;
}
pidptr->data_len_max = pidptr->data_len_max + 4096;
}
} else {
remaining = pidptr->data_len - pidptr->data_len_loaded;
buflen = buflen > remaining ? remaining : buflen;
}
memcpy(pidptr->data + pidptr->data_len_loaded,
bufstart,
buflen);
pidptr->data_len_loaded += buflen;
if (pidptr->data_len == 0 || pidptr->data_len_loaded < pidptr->data_len)
return 0;
// Indicate that next one starts from beginning
pidptr->data_len_loaded = 0;
return 1;
}
static mpeg2t_pid_t *mpeg2t_lookup_pid (mpeg2t_t *ptr,
uint16_t pid)
{
mpeg2t_pid_t *pidptr = &ptr->pas.pid;
while (pidptr != NULL && pidptr->pid != pid) {
pidptr = pidptr->next_pid;
}
return pidptr;
}
static void add_to_pidQ (mpeg2t_t *ptr, mpeg2t_pid_t *pidptr)
{
mpeg2t_pid_t *p = &ptr->pas.pid;
while (p->next_pid != NULL) {
p = p->next_pid;
}
p->next_pid = pidptr;
}
static void create_pmap (mpeg2t_t *ptr, uint16_t prog_num, uint16_t pid)
{
mpeg2t_pmap_t *pmap;
mpeg2t_message(LOG_INFO, "Adding pmap prog_num %x pid %x", prog_num, pid);
pmap = MALLOC_STRUCTURE(mpeg2t_pmap_t);
if (pmap == NULL) return;
memset(pmap, 0, sizeof(*pmap));
pmap->pid.pak_type = MPEG2T_PROG_MAP_PAK;
pmap->pid.pid = pid;
pmap->program_number = prog_num;
add_to_pidQ(ptr, &pmap->pid);
}
static void create_es (mpeg2t_t *ptr,
uint16_t pid,
uint8_t stream_type,
const uint8_t *es_data,
uint32_t es_info_len)
{
mpeg2t_es_t *es;
mpeg2t_message(LOG_INFO,
"Adding ES PID %x stream type %d", pid, stream_type);
es = MALLOC_STRUCTURE(mpeg2t_es_t);
if (es == NULL) return;
memset(es, 0, sizeof(*es));
es->pid.pak_type = MPEG2T_ES_PAK;
es->pid.pid = pid;
es->stream_type = stream_type;
if (es_info_len != 0) {
es->es_data = (uint8_t *)malloc(es_info_len);
if (es->es_data != NULL) {
memcpy(es->es_data, es_data, es_info_len);
es->es_info_len = es_info_len;
}
}
es->work_max_size = 4096;
add_to_pidQ(ptr, &es->pid);
}
static int mpeg2t_process_pas (mpeg2t_t *ptr, const uint8_t *buffer)
{
uint32_t buflen;
uint32_t section_len;
uint32_t len;
const uint8_t *mapptr;
uint16_t prog_num, pid;
const uint8_t *pasptr;
int ret;
buflen = 188;
// process pas pointer
pasptr = mpeg2t_transport_payload_start(buffer, &buflen);
if (pasptr == NULL) return 0;
if (mpeg2t_payload_unit_start_indicator(buffer) == 0) {
ret = mpeg2t_join_pak(&ptr->pas.pid,
pasptr,
buflen,
mpeg2t_continuity_counter(buffer));
if (ret <= 0) return 0; // not done, or bad
pasptr = ptr->pas.pid.data;
section_len = ptr->pas.pid.data_len;
} else {
if (*pasptr + 1 > buflen)
return 0;
buflen -= *pasptr + 1;
pasptr += *pasptr + 1; // go through the pointer field
if (*pasptr != 0 || (pasptr[1] & 0xc0) != 0x80) {
mpeg2t_message(LOG_ERR, "PAS field not 0");
return 0;
}
section_len = ((pasptr[1] << 8) | pasptr[2]) & 0x3ff;
// remove table_id, section length fields
pasptr += 3;
buflen -= 3;
if (buflen < section_len) {
mpeg2t_start_join_pak(&ptr->pas.pid,
pasptr, // start after section len
buflen,
section_len,
mpeg2t_continuity_counter(buffer));
return 0;
}
// At this point, pasptr points to transport_stream_id
}
ptr->pas.transport_stream_id = ((pasptr[0] << 8 | pasptr[1]));
ptr->pas.version_number = (pasptr[2] >> 1) & 0x1f;
mapptr = &pasptr[5];
section_len -= 5 + 4; // remove CRC and stuff before map list
for (len = 0; len < section_len; len += 4, mapptr += 4) {
prog_num = (mapptr[0] << 8) | mapptr[1];
if (prog_num != 0) {
pid = ((mapptr[2] << 8) | mapptr[3]) & 0x1fff;
if (mpeg2t_lookup_pid(ptr, pid) == NULL) {
create_pmap(ptr, prog_num, pid);
}
}
}
return 1;
}
static int mpeg2t_process_pmap (mpeg2t_t *ptr,
mpeg2t_pid_t *ifptr,
const uint8_t *buffer)
{
uint32_t buflen;
uint32_t section_len;
uint32_t len, es_len;
uint16_t prog_num, pcr_pid;
const uint8_t *pmapptr;
mpeg2t_pmap_t *pmap_pid = (mpeg2t_pmap_t *)ifptr;
int ret;
uint8_t stream_type;
uint16_t e_pid;
buflen = 188;
// process pas pointer
pmapptr = mpeg2t_transport_payload_start(buffer, &buflen);
if (pmapptr == NULL) return 0;
if (mpeg2t_payload_unit_start_indicator(buffer) == 0) {
ret = mpeg2t_join_pak(ifptr,
pmapptr,
buflen,
mpeg2t_continuity_counter(buffer));
if (ret <= 0) return 0;
pmapptr = ifptr->data;
section_len = ifptr->data_len;
} else {
if (*pmapptr + 1 > buflen)
return 0;
buflen -= *pmapptr + 1;
pmapptr += *pmapptr + 1; // go through the pointer field
if (*pmapptr != 2 || (pmapptr[1] & 0xc0) != 0x80) {
mpeg2t_message(LOG_ERR, "PMAP start field not 2");
return 0;
}
section_len = ((pmapptr[1] << 8) | pmapptr[2]) & 0x3ff;
pmapptr += 3;
buflen -= 3;
if (buflen < section_len) {
mpeg2t_start_join_pak(ifptr,
pmapptr,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -