/*
* build_ts.cpp
*
* History:
* 2011/4/17 - [Yi Zhu] created file
* 2014/12/16 - [Chengcai Jing] modified file
*
* Copyright (C) 2007-2008, Ambarella, Inc.
*
* All rights reserved. No Part of this file may be reproduced, stored
* in a retrieval system, or transmitted, in any form, or by any means,
* electronic, mechanical, photocopying, recording, or otherwise,
* without the prior consent of Ambarella, Inc.
*/
#include "am_define.h"
#include "am_media_types.h"
#include "am_muxer_ts_builder.h"
#ifndef WIN32
#include <sys/ioctl.h> //for ioctl
#include <fcntl.h> //for open O_* flags
#include <unistd.h> //for read/write/lseek
#endif
#include <time.h>
#include <string.h>
AMTsBuilder::AMTsBuilder()
{
m_ver.pat = 0;
m_ver.pmt = 0;
memset(&m_audio_info, 0, sizeof(m_audio_info));
}
void AMTsBuilder::destroy()
{
delete this;
}
AM_ERR AMTsBuilder::create_pat(AM_TS_MUXER_PSI_PAT_INFO *pat_info,
uint8_t *pat_buf)
{
MPEG_TS_TP_HEADER *ts_header = (MPEG_TS_TP_HEADER *) pat_buf;
/*TS hdr size(4B) + PSI pointer field(1B)*/
PAT_HDR *pat_header = (PAT_HDR *) (pat_buf + 5);
uint8_t *pat_content = (uint8_t *) (((uint8_t *) pat_header) + PAT_HDR_SIZE);
int crc32 = 0;
// TS HEADER
ts_header->sync_byte = MPEG_TS_TP_SYNC_BYTE;
ts_header->transport_error_indicator =
MPEG_TS_TRANSPORT_ERROR_INDICATOR_NO_ERRORS;
ts_header->payload_unit_start_indicator =
MPEG_TS_PAYLOAD_UNIT_START_INDICATOR_START;
ts_header->transport_priority = MPEG_TS_TRANSPORT_PRIORITY_PRIORITY;
ts_header->transport_scrambling_control = MPEG_TS_SCRAMBLING_CTRL_NOT_SCRAMBLED;
ts_header->adaptation_field_control = MPEG_TS_ADAPTATION_FIELD_PAYLOAD_ONLY;
ts_header->continuity_counter = 0;
MPEG_TS_TP_HEADER_PID_SET(ts_header, MPEG_TS_PAT_PID);
// Set PSI pointer field
pat_buf[4] = 0x00;
// PAT Header
pat_header->table_id = 0x00;
pat_header->section_syntax_indicator = 1;
pat_header->b0 = 0;
pat_header->reserved0 = 0x3;
pat_header->transport_stream_id_l = 0x00;
pat_header->transport_stream_id_h = 0x00;
pat_header->reserved1 = 0x3;
pat_header->version_number = m_ver.pat;
pat_header->current_next_indicator = 1;
pat_header->section_number = 0x0;
pat_header->last_section_number = 0x0;
pat_header->section_length0to7 = 0; //Update later
pat_header->section_length8to11 = 0; //Update later
// add informations for all programs (only one for now)
pat_content[0] = (pat_info->prg_info->prg_num >> 8) & 0xff;
pat_content[1] = pat_info->prg_info->prg_num & 0xff;
pat_content[2] = 0xE0 | ((pat_info->prg_info->pid_pmt & 0x1fff) >> 8);
pat_content[3] = pat_info->prg_info->pid_pmt & 0xff;
pat_content += 4;
// update patHdr.section_length
uint16_t section_len = pat_content + 4 - (uint8_t *) pat_header - 3;
pat_header->section_length8to11 = (section_len & 0x0fff) >> 8;
pat_header->section_length0to7 = (section_len & 0x00ff);
// Calc CRC32
crc32 = cal_crc32((uint8_t*) pat_header,
(int) (pat_content - (uint8_t *) pat_header));
pat_content[0] = (crc32 >> 24) & 0xff;
pat_content[1] = (crc32 >> 16) & 0xff;
pat_content[2] = (crc32 >> 8) & 0xff;
pat_content[3] = crc32 & 0xff;
// Stuff rest of the packet
memset(pat_content + 4, /*Stuffing Btypes*/
0xff, MPEG_TS_TP_PACKET_SIZE - (pat_content + 4 - pat_buf));
return ME_OK;
}
AM_ERR AMTsBuilder::update_psi_cc(uint8_t * buf_ts)
{
((MPEG_TS_TP_HEADER *) buf_ts)->continuity_counter ++;
return ME_OK;
}
AM_ERR AMTsBuilder::create_pmt(AM_TS_MUXER_PSI_PMT_INFO *pmt_info, uint8_t *pmt_buf)
{
MPEG_TS_TP_HEADER *ts_header = (MPEG_TS_TP_HEADER *) pmt_buf;
PMT_HDR *PMT_header = (PMT_HDR *) (pmt_buf + 5);
uint8_t *PMT_content = (uint8_t *) (((uint8_t *) PMT_header) + PMT_HDR_SIZE);
int crc32;
// TS HEADER
ts_header->sync_byte = MPEG_TS_TP_SYNC_BYTE;
ts_header->transport_error_indicator =
MPEG_TS_TRANSPORT_ERROR_INDICATOR_NO_ERRORS;
ts_header->payload_unit_start_indicator =
MPEG_TS_PAYLOAD_UNIT_START_INDICATOR_START;
ts_header->transport_priority = MPEG_TS_TRANSPORT_PRIORITY_PRIORITY;
MPEG_TS_TP_HEADER_PID_SET(ts_header, pmt_info->prg_info->pid_pmt);
ts_header->transport_scrambling_control = MPEG_TS_SCRAMBLING_CTRL_NOT_SCRAMBLED;
ts_header->adaptation_field_control = MPEG_TS_ADAPTATION_FIELD_PAYLOAD_ONLY;
ts_header->continuity_counter = 0;
// Set PSI poiter field
pmt_buf[4] = 0x00;
// PMT HEADER
PMT_header->table_id = 0x02;
PMT_header->section_syntax_indicator = 1;
PMT_header->b0 = 0;
PMT_header->reserved0 = 0x3;
PMT_header->section_length0to7 = 0; //update later
PMT_header->section_length8to11 = 0; //update later
PMT_header->program_number_h = (pmt_info->prg_info->prg_num >> 8) & 0xff;
PMT_header->program_number_l = pmt_info->prg_info->prg_num & 0xff;
PMT_header->reserved1 = 0x3;
PMT_header->version_number = m_ver.pmt;
PMT_header->current_next_indicator = 1;
PMT_header->section_number = 0x0;
PMT_header->last_section_number = 0x0;
PMT_header->reserved2 = 0x7;
PMT_header->pcr_pid8to12 = (pmt_info->prg_info->pid_pcr >> 8) & 0x1f;
PMT_header->pcr_pid0to7 = pmt_info->prg_info->pid_pcr & 0xff;
PMT_header->reserved3 = 0xf;
if (pmt_info->descriptor_len == 0) {
PMT_header->program_info_length0to7 = 0;
PMT_header->program_info_length8to11 = 0;
} else {
PMT_header->program_info_length8to11 = ((2 + pmt_info->descriptor_len) >> 8)
& 0x0f;
PMT_header->program_info_length0to7 = ((2 + pmt_info->descriptor_len)
& 0xff);
}
if (pmt_info->descriptor_len > 0) {
PMT_content[0] = pmt_info->descriptor_tag;
PMT_content[1] = pmt_info->descriptor_len;
memcpy(&PMT_content[2], pmt_info->descriptor, pmt_info->descriptor_len);
PMT_content += (2 + pmt_info->descriptor_len);
}
//// Add all stream elements
//for (uint16_t strNum = 0; strNum < pmt_info->total_stream; ++ strNum) {
for (uint16_t strNum = 0; strNum < 2; ++strNum) {
AM_TS_MUXER_PSI_STREAM_INFO * str_info = pmt_info->stream[strNum];
PMT_ELEMENT *PMT_element = (PMT_ELEMENT *) PMT_content;
PMT_element->stream_type = str_info->type;
PMT_element->reserved0 = 0x7; // 3 bits
PMT_element->elementary_pid8to12 = ((str_info->pid & 0x1fff) >> 8);
PMT_element->elementary_pid0to7 = (str_info->pid & 0xff);
PMT_element->reserved1 = 0xf; // 4 bits
PMT_element->es_info_length_h = (((str_info->descriptor_len + 2) >> 8) & 0x0f);
PMT_element->ES_info_length_l = (str_info->descriptor_len + 2) & 0xff;
PMT_content += PMT_ELEMENT_SIZE;
PMT_content[0] = str_info->descriptor_tag; //descriptor_tag
PMT_content[1] = str_info->descriptor_len; //descriptor_length
if (str_info->descriptor_len > 0) {
memcpy(&PMT_content[2], str_info->descriptor, str_info->descriptor_len);
}
PMT_content += (2 + str_info->descriptor_len);
}
// update pmtHdr.section_length
uint16_t section_len = PMT_content + 4 - ((uint8_t *) PMT_header + 3);
PMT_header->section_length8to11 = (section_len >> 8) & 0x0f;
PMT_header->section_length0to7 = (section_len & 0xff);
// Calc CRC32
crc32 = cal_crc32((uint8_t*) PMT_header,
(int) (PMT_content - (uint8_t*) PMT_header));
PMT_content[0] = (crc32 >> 24) & 0xff;
PMT_content[1] = (crc32 >> 16) & 0xff;
PMT_content[2] = (crc32 >> 8) & 0xff;
PMT_content[3] = crc32 & 0xff;
// Stuff rest of the packet
memset((PMT_content + 4), 0xff,
(MPEG_TS_TP_PACKET_SIZE - (((uint8_t*) PMT_content + 4) - pmt_buf)));
return ME_OK;
}
AM_ERR AMTsBuilder::create_pcr(uint16_t pcr_pid, uint8_t *pcr_buf)
{
MPEG_TS_TP_HEADER *ts_header = (MPEG_TS_TP_HEADER *) pcr_buf;
uint8_t *adaptation_field = (uint8_t*) (pcr_buf +
MPEG_TS_TP_PACKET_HEADER_SIZE);
// TS HEADER
ts_header->sync_byte = MPEG_TS_TP_SYNC_BYTE;
ts_header->transport_error_indicator =
MPEG_TS_TRANSP