diff --git a/src/driver/genpsi.cpp b/src/driver/genpsi.cpp index 4f11d2d03..6cdcf6d99 100644 --- a/src/driver/genpsi.cpp +++ b/src/driver/genpsi.cpp @@ -35,6 +35,7 @@ #define ES_TYPE_MPEG12 0x02 #define ES_TYPE_AVC 0x1b #define ES_TYPE_MPA 0x03 +#define ES_TYPE_EAC3 0x7a #define ES_TYPE_AC3 0x81 static const uint32_t crc_table[256] = { @@ -83,43 +84,6 @@ static const uint32_t crc_table[256] = { 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 }; -//-- special enigma stream description packet for -- -//-- at least 1 video, 1 audo and 1 PCR-Pid stream -- -//------------------------------------------------------------------------------------ -static uint8_t pkt_enigma[] = -{ - 0x47, 0x40, 0x1F, 0x10, 0x00, - 0x7F, 0x80, 0x24, - 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x6D, 0x66, 0x30, 0x19, - 0x80, 0x13, 'N','E','U','T','R','I','N','O','N','G', // tag(8), len(8), text(10) -> NG hihi ;) - 0x00, 0x02, 0x00, 0x6e, // cVPID(8), len(8), PID(16) - 0x01, 0x03, 0x00, 0x78, 0x00, // cAPID(8), len(8), PID(16), ac3flag(8) -// 0x02, 0x02, 0x00, 0x82,// cTPID(8), len(8), ... - 0x03, 0x02, 0x00, 0x6e // cPCRPID(8), ... -}; -//-- PAT packet for at least 1 PMT -- -//---------------------------------------------------------- -static uint8_t pkt_pat[] = -{ - 0x47, 0x40, 0x00, 0x10, 0x00, // HEADER-1 - 0x00, 0xB0, 0x0D, // HEADER-2 - 0x04, 0x37, 0xE9, 0x00, 0x00, // HEADER-3 sid - 0x6D, 0x66, 0xEF, 0xFF, // PAT-DATA - PMT (PID=0xFFF) entry -}; - -//-- PMT packet for at least 1 video and 1 audio stream -- -//-------------------------------------------------------- -static uint8_t pkt_pmt[] = -{ - 0x47, 0x4F, 0xFF, 0x10, 0x00, // HEADER-1 - 0x02, 0xB0, 0x17, // HEADER-2 - 0x6D, 0x66, 0xE9, 0x00, 0x00, // HEADER-3 - 0xE0, 0x00, 0xF0, 0x00, // PMT-DATA - 0x02, 0xE0, 0x00, 0xF0, 0x00, // (video stream 1) - 0x03, 0xE0, 0x00, 0xF0, 0x00 // (audio stream 1) -}; - CGenPsi::CGenPsi() { nba = 0; @@ -128,13 +92,12 @@ CGenPsi::CGenPsi() pcrpid=0; vtxtpid = 0; - vtxtlang[0] = 'g'; - vtxtlang[1] = 'e'; - vtxtlang[2] = 'r'; memset(apid, 0, sizeof(apid)); memset(atypes, 0, sizeof(atypes)); nsub = 0; memset(dvbsubpid, 0, sizeof(dvbsubpid)); + neac3 = 0; + memset(eac3_pid, 0, sizeof(eac3_pid)); } uint32_t CGenPsi::calc_crc32psi(uint8_t *dst, const uint8_t *src, uint32_t len) @@ -174,6 +137,15 @@ void CGenPsi::addPid(uint16_t pid, uint16_t pidtype, short isAC3, const char *da case EN_TYPE_AUDIO: apid[nba]=pid; atypes[nba]=isAC3; + if(data != NULL){ + apid_lang[nba][0] = data[0]; + apid_lang[nba][1] = data[1]; + apid_lang[nba][2] = data[2]; + }else{ + apid_lang[nba][0] = 'u'; + apid_lang[nba][1] = 'n'; + apid_lang[nba][2] = 'k'; + } nba++; break; case EN_TYPE_TELTEX: @@ -182,6 +154,10 @@ void CGenPsi::addPid(uint16_t pid, uint16_t pidtype, short isAC3, const char *da vtxtlang[0] = data[0]; vtxtlang[1] = data[1]; vtxtlang[2] = data[2]; + }else{ + vtxtlang[0] = 'u'; + vtxtlang[1] = 'n'; + vtxtlang[2] = 'k'; } break; case EN_TYPE_DVBSUB: @@ -190,165 +166,221 @@ void CGenPsi::addPid(uint16_t pid, uint16_t pidtype, short isAC3, const char *da dvbsublang[nsub][0] = data[0]; dvbsublang[nsub][1] = data[1]; dvbsublang[nsub][2] = data[2]; + }else{ + dvbsublang[nsub][0] = 'u'; + dvbsublang[nsub][1] = 'n'; + dvbsublang[nsub][2] = 'k'; } nsub++; break; + case EN_TYPE_AUDIO_EAC3: + eac3_pid[neac3] = pid; + if(data != NULL){ + eac3_lang[neac3][0] = data[0]; + eac3_lang[neac3][1] = data[1]; + eac3_lang[neac3][2] = data[2]; + }else{ + eac3_lang[neac3][0] = 'u'; + eac3_lang[neac3][1] = 'n'; + eac3_lang[neac3][2] = 'k'; + } + neac3++; + break; default: break; } } -//== setup a new TS packet with format == -//== predefined with a template == -//======================================= -#define COPY_TEMPLATE(dst, src) copy_template(dst, src, sizeof(src)) +void CGenPsi::build_pat(uint8_t* buffer) +{ + buffer[0x00] = 0x47; + buffer[0x01] = 0x40; + buffer[0x02] = 0x00; // PID = 0x0000 + buffer[0x03] = 0x10 ; -int CGenPsi::copy_template(uint8_t *dst, uint8_t *src, int len) -{ -//-- reset buffer -- - memset(dst, 0xFF, SIZE_TS_PKT); -//-- copy PMT template -- - memmove(dst, src, len); + buffer[0x04] = 0x00; // CRC calculation begins here + buffer[0x05] = 0x00; // 0x00: Program association section + buffer[0x06] = 0xb0; + buffer[0x07] = 0x11; // section_length + buffer[0x08] = 0x00; + buffer[0x09] = 0xbb; // TS id = 0x00b0 + buffer[0x0a] = 0xc1; + // section # and last section # + buffer[0x0b] = buffer[0x0c] = 0x00; + // Network PID (useless) + buffer[0x0d] = buffer[0x0e] = 0x00; + buffer[0x0f] = 0xe0; + buffer[0x10] = 0x10; - return len; + // Program Map PID + buffer[0x11] = 0x03; + buffer[0x12] = 0xe8; + buffer[0x13] = 0xe0; + buffer[0x14] = pmt_pid; + + // Put CRC in buffer[0x15...0x18] + calc_crc32psi(&buffer[0x15], &buffer[OFS_HDR_2], 0x15-OFS_HDR_2 ); + + // needed stuffing bytes + for (int i=0x19; i < 188; i++) + { + buffer[i]=0xff; + } +} + +void CGenPsi::build_pmt(uint8_t* buffer) +{ + int off=0; + + buffer[0x00] = 0x47; + buffer[0x01] = 0x40; + buffer[0x02] = pmt_pid; + buffer[0x03] = 0x10; + buffer[0x04] = 0x00; // CRC calculation begins here + buffer[0x05] = 0x02; // 0x02: Program map section + buffer[0x06] = 0xb0; + buffer[0x07] = 0x20; // section_length + buffer[0x08] = 0x03; + buffer[0x09] = 0xe8; // prog number + buffer[0x0a] = 0xc1; + // section # and last section # + buffer[0x0b] = buffer[0x0c] = 0x00; + // Program Clock Reference (PCR) PID + buffer[0x0d] = pcrpid>>8; + buffer[0x0e] = pcrpid&0xff; + // program_info_length == 0 + buffer[0x0f] = 0xf0; + buffer[0x10] = 0x00; + // Video PID + buffer[0x11] = vtype; // video stream type + buffer[0x12] = vpid>>8; + buffer[0x13] = vpid&0xff; + buffer[0x14] = 0xf0; + buffer[0x15] = 0x09; // es info length + // useless info + buffer[0x16] = 0x07; + buffer[0x17] = 0x04; + buffer[0x18] = 0x08; + buffer[0x19] = 0x80; + buffer[0x1a] = 0x24; + buffer[0x1b] = 0x02; + buffer[0x1c] = 0x11; + buffer[0x1d] = 0x01; + buffer[0x1e] = 0xfe; + off = 0x1e; + + // Audio streams + for (int index = 0; index < nba && index<10; index++) + { + buffer[++off] = (atypes[index]==1)? ES_TYPE_AC3 : ES_TYPE_MPA; + buffer[++off] = apid[index]>>8; + buffer[++off] = apid[index]&0xff; + + if (atypes[index] == ES_TYPE_AC3) + { + buffer[++off] = 0xf0; + buffer[++off] = 0x0c; // es info length + buffer[++off] = 0x05; + buffer[++off] = 0x04; + buffer[++off] = 0x41; + buffer[++off] = 0x43; + buffer[++off] = 0x2d; + buffer[++off] = 0x33; + } + else + { + buffer[++off] = 0xf0; + buffer[++off] = 0x06; // es info length + } + buffer[++off] = 0x0a; // iso639 descriptor tag + buffer[++off] = 0x04; // descriptor length + buffer[++off] = apid_lang[index][0]; + buffer[++off] = apid_lang[index][1]; + buffer[++off] = apid_lang[index][2]; + buffer[++off] = 0x00; // audio type + } + // eac3 audio + for (int index=0; index>8; + buffer[++off] = eac3_pid[index] & 0xFF; + buffer[++off] = 0xF0; + buffer[++off] = 0x13-6; // es info length + buffer[++off] = 0x52; + buffer[++off] = 0x01; + buffer[++off] = 0x5d; + buffer[++off] = 0x0a; // iso639 descriptor tag + buffer[++off] = 0x04; // descriptor length + buffer[++off] = eac3_lang[index][0]; //language code[0] + buffer[++off] = eac3_lang[index][1]; //language code[1] + buffer[++off] = eac3_lang[index][2]; //language code[2] + buffer[++off] = 0x01; + buffer[++off] = 0x7a; + buffer[++off] = 0x02; + buffer[++off] = 0x80; + buffer[++off] = 0xc5; + } + + // Subtitle streams + for (int index = 0; index < nsub && index<10; index++) + { + buffer[++off] = 0x06;//pes private type; + buffer[++off] = dvbsubpid[index]>>8; + buffer[++off] = dvbsubpid[index]&0xff; + buffer[++off] = 0xf0; + buffer[++off] = 0x0a; // es info length + buffer[++off] = 0x59; // DVB sub tag + buffer[++off] = 0x08; // descriptor length + buffer[++off] = dvbsublang[index][0]; + buffer[++off] = dvbsublang[index][1]; + buffer[++off] = dvbsublang[index][2]; + buffer[++off] = 0x20; //subtitle_stream.subtitling_type + buffer[++off] = 0x01>>8; //composition_page_id + buffer[++off] = 0x01&0xff; //composition_page_id + buffer[++off] = 0x01>>8; //ancillary_page_id + buffer[++off] = 0x01&0xff; //ancillary_page_id + } + + // TeleText streams + if(vtxtpid){ + buffer[++off] = 0x06; //teletext stream type; + buffer[++off] = 0xE0 | vtxtpid>>8; + buffer[++off] = vtxtpid&0xff; + buffer[++off] = 0xf0; + buffer[++off] = 0x0A; // ES_info_length + buffer[++off] = 0x52; //DVB-DescriptorTag: 82 (0x52) [= stream_identifier_descriptor] + buffer[++off] = 0x01; // descriptor_length + buffer[++off] = 0x03; //component_tag + buffer[++off] = 0x56; // DVB teletext tag + buffer[++off] = 0x05; // descriptor length + buffer[++off] = vtxtlang[0]; //language code[0] + buffer[++off] = vtxtlang[1]; //language code[1] + buffer[++off] = vtxtlang[2]; //language code[2] + buffer[++off] = (/*descriptor_magazine_number*/ 0x01 & 0x06) | ((/*descriptor_type*/ 0x01 << 3) & 0xF8); + buffer[++off] = 0x00 ; //Teletext_page_number + } + buffer[0x07] = off-3; // update section_length + + // Put CRC in ts[0x29...0x2c] + calc_crc32psi(&buffer[off+1], &buffer[OFS_HDR_2], off+1-OFS_HDR_2 ); + + // needed stuffing bytes + for (int i=off+5 ; i < 188 ; i++) + { + buffer[i] = 0xff; + } } int CGenPsi::genpsi(int fd) { - uint8_t pkt[SIZE_TS_PKT]; - int i, data_len, patch_len, ofs; + uint8_t buffer[SIZE_TS_PKT]; - //-- copy "Enigma"-template -- - data_len = COPY_TEMPLATE(pkt, pkt_enigma); + build_pat(buffer); + write(fd, buffer, SIZE_TS_PKT); - //-- adjust len dependent to number of audio streams -- - data_len += ((SIZE_ENIGMA_TAB_ROW+1) * (nba-1)); - - patch_len = data_len - OFS_HDR_2 + 1; - pkt[OFS_HDR_2+1] |= (patch_len>>8); - pkt[OFS_HDR_2+2] = (patch_len & 0xFF); - //-- write row with desc. for video stream -- - ofs = OFS_ENIGMA_TAB; - pkt[ofs] = EN_TYPE_VIDEO; - pkt[ofs+1] = 0x02; - pkt[ofs+2] = (vpid>>8); - pkt[ofs+3] = (vpid & 0xFF); - //-- for each audio stream, write row with desc. -- - ofs += SIZE_ENIGMA_TAB_ROW; - for (i=0; i>8); - pkt[ofs+3] = (apid[i] & 0xFF); - pkt[ofs+4] = (atypes[i]==1)? 0x01 : 0x00; - - ofs += (SIZE_ENIGMA_TAB_ROW + 1); - } - //-- write row with desc. for pcr stream (eq. video) -- - pkt[ofs] = EN_TYPE_PCR; - pkt[ofs+1] = 0x02; - pkt[ofs+2] = (pcrpid>>8); - pkt[ofs+3] = (pcrpid & 0xFF); - - //-- calculate CRC -- - calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 ); - //-- write TS packet -- - write(fd, pkt, SIZE_TS_PKT); - - //-- (II) build PAT -- - data_len = COPY_TEMPLATE(pkt, pkt_pat); -// pkt[0xf]= 0xE0 | (pmtpid>>8); -// pkt[0x10] = pmtpid & 0xFF; - //-- calculate CRC -- - calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 ); - //-- write TS packet -- - write(fd, pkt, SIZE_TS_PKT); - - //-- (III) build PMT -- - data_len = COPY_TEMPLATE(pkt, pkt_pmt); - //-- adjust len dependent to count of audio streams -- - data_len += (SIZE_STREAM_TAB_ROW * (nba-1)); - if(vtxtpid){ - data_len += (SIZE_STREAM_TAB_ROW * (1))+10;//add teletext row length - } - if(nsub){ - data_len += ((SIZE_STREAM_TAB_ROW+10) * nsub);//add dvbsub row length - } - patch_len = data_len - OFS_HDR_2 + 1; - pkt[OFS_HDR_2+1] |= (patch_len>>8); - pkt[OFS_HDR_2+2] = (patch_len & 0xFF); - //-- patch pcr PID -- - ofs = OFS_PMT_DATA; - pkt[ofs] |= (pcrpid>>8); - pkt[ofs+1] = (pcrpid & 0xFF); - //-- write row with desc. for ES video stream -- - ofs = OFS_STREAM_TAB; - pkt[ofs] = vtype; - pkt[ofs+1] = 0xE0 | (vpid>>8); - pkt[ofs+2] = (vpid & 0xFF); - pkt[ofs+3] = 0xF0; - pkt[ofs+4] = 0x00; - - //-- for each ES audio stream, write row with desc. -- - for (i=0; i>8); - pkt[ofs+2] = (apid[i] & 0xFF); - pkt[ofs+3] = 0xF0; - pkt[ofs+4] = 0x00; - } - - //teletext - if(vtxtpid){ - ofs += SIZE_STREAM_TAB_ROW; - pkt[ofs] = 0x06; //teletext stream type; - pkt[ofs+1] = 0xE0 | vtxtpid>>8; - pkt[ofs+2] = vtxtpid&0xff; - pkt[ofs+3] = 0xf0; - pkt[ofs+4] = 0x0A; // ES_info_length - pkt[ofs+5] = 0x52; //DVB-DescriptorTag: 82 (0x52) [= stream_identifier_descriptor] - pkt[ofs+6] = 0x01; // descriptor_length - pkt[ofs+7] = 0x03; //component_tag - pkt[ofs+8] = 0x56; // DVB teletext tag - pkt[ofs+9] = 0x05; // descriptor length - pkt[ofs+10] = vtxtlang[0]; //language code[0] - pkt[ofs+11] = vtxtlang[1]; //language code[1] - pkt[ofs+12] = vtxtlang[2]; //language code[2] - pkt[ofs+13] = (/*descriptor_magazine_number*/ 0x01 & 0x06) | ((/*descriptor_type*/ 0x01 << 3) & 0xF8); - pkt[ofs+14] = 0x00 ; //Teletext_page_number - } - - //dvbsub - for (i=0; i 0 || vtxtpid) - ofs += 10; - - pkt[ofs] = 0x06;//subtitle stream type; - pkt[ofs+1] = 0xE0 | dvbsubpid[i]>>8; - pkt[ofs+2] = dvbsubpid[i] & 0xFF; - pkt[ofs+3] = 0xF0; - pkt[ofs+4] = 0x0A; // es info length - pkt[ofs+5] = 0x59; // DVB sub tag - pkt[ofs+6] = 0x08; // descriptor length - pkt[ofs+7] = dvbsublang[i][0]; //language code[0] - pkt[ofs+8] = dvbsublang[i][1]; //language code[1] - pkt[ofs+9] = dvbsublang[i][2]; //language code[2] - pkt[ofs+10] = 0x20; //subtitle_stream.subtitling_type - pkt[ofs+11] = 0x01>>8; //composition_page_id - pkt[ofs+12] = 0x01&0xff; //composition_page_id - pkt[ofs+13] = 0x01>>8; //ancillary_page_id - pkt[ofs+14] = 0x01&0xff; //ancillary_page_id - } - - //-- calculate CRC -- - calc_crc32psi(&pkt[data_len], &pkt[OFS_HDR_2], data_len-OFS_HDR_2 ); - //-- write TS packet -- - write(fd, pkt, SIZE_TS_PKT); + build_pmt(buffer); + write(fd, buffer, SIZE_TS_PKT); //-- finish -- vpid=0; @@ -356,6 +388,9 @@ int CGenPsi::genpsi(int fd) nba=0; nsub = 0; vtxtpid = 0; + neac3 = 0; fdatasync(fd); return 1; + } + diff --git a/src/driver/genpsi.h b/src/driver/genpsi.h index bc39991aa..b34ff8510 100644 --- a/src/driver/genpsi.h +++ b/src/driver/genpsi.h @@ -23,17 +23,19 @@ #define __genpsi_h__ #include -#define EN_TYPE_VIDEO 0x00 -#define EN_TYPE_AUDIO 0x01 -#define EN_TYPE_TELTEX 0x02 -#define EN_TYPE_PCR 0x03 -#define EN_TYPE_AVC 0x04 -#define EN_TYPE_DVBSUB 0x06 +#define EN_TYPE_VIDEO 0x00 +#define EN_TYPE_AUDIO 0x01 +#define EN_TYPE_TELTEX 0x02 +#define EN_TYPE_PCR 0x03 +#define EN_TYPE_AVC 0x04 +#define EN_TYPE_DVBSUB 0x06 +#define EN_TYPE_AUDIO_EAC3 0x07 class CGenPsi { private: - short nba, nsub; + static const unsigned int pmt_pid = 0xcc; + short nba, nsub, neac3; uint16_t vpid; uint8_t vtype; uint16_t pcrpid; @@ -41,10 +43,14 @@ class CGenPsi char vtxtlang[3]; uint16_t apid[10]; short atypes[10]; + char apid_lang[10][3]; uint16_t dvbsubpid[10]; char dvbsublang[10][3]; - static int copy_template(uint8_t *dst, uint8_t *src, int len); + uint16_t eac3_pid[10]; + char eac3_lang[10][3]; uint32_t calc_crc32psi(uint8_t *dst, const uint8_t *src, uint32_t len); + void build_pat(uint8_t* buffer); + void build_pmt(uint8_t* buffer); public: CGenPsi(); diff --git a/src/driver/record.cpp b/src/driver/record.cpp index 6df68848e..d9541c3bf 100644 --- a/src/driver/record.cpp +++ b/src/driver/record.cpp @@ -171,7 +171,10 @@ record_error_msg_t CRecordInstance::Start(CZapitChannel * channel) } for (unsigned int i = 0; i < recMovieInfo->audioPids.size(); i++) { apids[numpids++] = recMovieInfo->audioPids[i].epgAudioPid; - psi.addPid(recMovieInfo->audioPids[i].epgAudioPid, EN_TYPE_AUDIO, recMovieInfo->audioPids[i].atype); + if(channel->getAudioChannel(i)->audioChannelType == CZapitAudioChannel::EAC3){ + psi.addPid(recMovieInfo->audioPids[i].epgAudioPid, EN_TYPE_AUDIO_EAC3, recMovieInfo->audioPids[i].atype, channel->getAudioChannel(i)->description.c_str()); + }else + psi.addPid(recMovieInfo->audioPids[i].epgAudioPid, EN_TYPE_AUDIO, recMovieInfo->audioPids[i].atype, channel->getAudioChannel(i)->description.c_str()); } if ((StreamVTxtPid) && (allpids.PIDs.vtxtpid != 0)){ apids[numpids++] = allpids.PIDs.vtxtpid; diff --git a/src/driver/streamts.cpp b/src/driver/streamts.cpp index 9e52136aa..8df0b0580 100644 --- a/src/driver/streamts.cpp +++ b/src/driver/streamts.cpp @@ -373,6 +373,7 @@ bool CStreamManager::Parse(int fd, stream_pids_t &pids, t_channel_id &chid) pids.insert(channel->getVideoPid()); for (int i = 0; i < channel->getAudioChannelCount(); i++) pids.insert(channel->getAudioChannel(i)->pid); + } CGenPsi psi; for (stream_pids_t::iterator it = pids.begin(); it != pids.end(); ++it) { @@ -384,7 +385,11 @@ bool CStreamManager::Parse(int fd, stream_pids_t &pids, t_channel_id &chid) if (*it == channel->getAudioChannel(i)->pid) { CZapitAudioChannel::ZapitAudioChannelType atype = channel->getAudioChannel(i)->audioChannelType; printf("CStreamManager::Parse: genpsi apid %x (%d)\n", *it, atype); - psi.addPid(*it, EN_TYPE_AUDIO, atype); + if(channel->getAudioChannel(i)->audioChannelType == CZapitAudioChannel::EAC3){ + psi.addPid(*it, EN_TYPE_AUDIO_EAC3, atype, channel->getAudioChannel(i)->description.c_str()); + }else{ + psi.addPid(*it, EN_TYPE_AUDIO, atype, channel->getAudioChannel(i)->description.c_str()); + } } } }