mirror of https://github.com/q191201771/lal.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
333 lines
8.8 KiB
Go
333 lines
8.8 KiB
Go
// Copyright 2023, Chef. All rights reserved.
|
|
// https://github.com/q191201771/lal
|
|
//
|
|
// Use of this source code is governed by a MIT-style license
|
|
// that can be found in the License file.
|
|
//
|
|
// Author: Chef (191201771@qq.com)
|
|
|
|
package mpegts
|
|
|
|
import (
|
|
"github.com/q191201771/naza/pkg/bele"
|
|
"github.com/q191201771/naza/pkg/nazabits"
|
|
)
|
|
|
|
// PsiId
|
|
const (
|
|
TsPsiIdPas = 0x00 // program_association_section
|
|
TsPsiIdCas = 0x01 // conditional_access_section (CA_section)
|
|
TsPsiIdPms = 0x02 // TS_program_map_section
|
|
TsPsiIdDs = 0x03 // TS_description_section
|
|
TsPsiIdSds = 0x04 // ISO_IEC_14496_scene_description_section
|
|
TsPsiIdOds = 0x05 // ISO_IEC_14496_object_descriptor_section
|
|
TsPsiIdIso138181Start = 0x06 // ITU-T Rec. H.222.0 | ISO/IEC 13818-1 reserved
|
|
TsPsiIdIso138181End = 0x37
|
|
TsPsiIdIso138186Start = 0x38 // Defined in ISO/IEC 13818-6
|
|
TsPsiIdIso138186End = 0x3F
|
|
TsPsiIdUserStart = 0x40 // User private
|
|
TsPsiIdUserEnd = 0xFE
|
|
TsPsiIdForbidden = 0xFF // forbidden
|
|
)
|
|
|
|
const (
|
|
DescriptorTagAC3 = 0x6a
|
|
DescriptorTagAVCVideo = 0x28
|
|
DescriptorTagComponent = 0x50
|
|
DescriptorTagContent = 0x54
|
|
DescriptorTagDataStreamAlignment = 0x6
|
|
DescriptorTagEnhancedAC3 = 0x7a
|
|
DescriptorTagExtendedEvent = 0x4e
|
|
DescriptorTagExtension = 0x7f
|
|
DescriptorTagISO639LanguageAndAudioType = 0xa
|
|
DescriptorTagLocalTimeOffset = 0x58
|
|
DescriptorTagMaximumBitrate = 0xe
|
|
DescriptorTagNetworkName = 0x40
|
|
DescriptorTagParentalRating = 0x55
|
|
DescriptorTagPrivateDataIndicator = 0xf
|
|
DescriptorTagPrivateDataSpecifier = 0x5f
|
|
DescriptorTagRegistration = 0x5
|
|
DescriptorTagService = 0x48
|
|
DescriptorTagShortEvent = 0x4d
|
|
DescriptorTagStreamIdentifier = 0x52
|
|
DescriptorTagSubtitling = 0x59
|
|
DescriptorTagTeletext = 0x56
|
|
DescriptorTagVBIData = 0x45
|
|
DescriptorTagVBITeletext = 0x46
|
|
)
|
|
|
|
const (
|
|
opusIdentifier = 0x4f707573 // Opus
|
|
)
|
|
|
|
type PsiSection struct {
|
|
pointerFileld uint8
|
|
sectionData PsiSectionData
|
|
}
|
|
|
|
type PsiSectionData struct {
|
|
header PsiTableHeader
|
|
section PsiTableSyntaxSection
|
|
patData PatSpecificData
|
|
pmtData PmtSpecificData
|
|
}
|
|
|
|
type PsiTableHeader struct {
|
|
tableId uint8
|
|
sectionSyntaxIndicator uint8
|
|
sectionLength uint16
|
|
}
|
|
|
|
type PsiTableSyntaxSection struct {
|
|
tableIdExtension uint16
|
|
versionNumber uint8
|
|
currentNextIndicator uint8
|
|
sectionNumber uint8
|
|
lastSectionNumber uint8
|
|
tableData []byte
|
|
crc32 uint32
|
|
}
|
|
|
|
type PatSpecificData struct {
|
|
pes []PatProgramElement
|
|
}
|
|
|
|
type PmtSpecificData struct {
|
|
pcrPid uint16
|
|
programInfoLength uint16
|
|
pes []PmtProgramElement
|
|
}
|
|
|
|
func NewPsi() *PsiSection {
|
|
return &PsiSection{
|
|
pointerFileld: 0x00,
|
|
}
|
|
}
|
|
|
|
func (psi *PsiSection) Pack() (int, []byte) {
|
|
psiSection := make([]byte, 1+3+psi.calcPsiSectionLength())
|
|
bw := nazabits.NewBitWriter(psiSection)
|
|
|
|
bw.WriteBits8(8, psi.pointerFileld)
|
|
psi.writePsiTableHeader(&bw)
|
|
psi.writePsiTableSyntaxSection(&bw)
|
|
|
|
crc := CalcCrc32(0xffffffff, psiSection[1:len(psiSection)-4])
|
|
bele.LePutUint32(psiSection[4+psi.calcPsiSectionLength()-4:], crc)
|
|
|
|
return int(1 + 3 + psi.calcPsiSectionLength()), psiSection
|
|
}
|
|
|
|
func (psi *PsiSection) writePsiTableHeader(bw *nazabits.BitWriter) {
|
|
bw.WriteBits8(8, psi.sectionData.header.tableId)
|
|
bw.WriteBit(psi.sectionData.header.sectionSyntaxIndicator)
|
|
bw.WriteBit(0)
|
|
bw.WriteBits8(2, 0xff)
|
|
|
|
psi.sectionData.header.sectionLength = psi.calcPsiSectionLength()
|
|
bw.WriteBits16(12, psi.sectionData.header.sectionLength)
|
|
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) writePsiTableSyntaxSection(bw *nazabits.BitWriter) {
|
|
psi.writePsiTableSyntaxSectionHeader(bw)
|
|
psi.writePsiTableSyntaxSectionData(bw)
|
|
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) writePsiTableSyntaxSectionHeader(bw *nazabits.BitWriter) {
|
|
bw.WriteBits16(16, psi.sectionData.section.tableIdExtension)
|
|
bw.WriteBits8(2, 0xff)
|
|
bw.WriteBits8(5, psi.sectionData.section.versionNumber)
|
|
bw.WriteBit(psi.sectionData.section.currentNextIndicator)
|
|
bw.WriteBits8(8, psi.sectionData.section.sectionNumber)
|
|
bw.WriteBits8(8, psi.sectionData.section.lastSectionNumber)
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) writePsiTableSyntaxSectionData(bw *nazabits.BitWriter) {
|
|
switch psi.sectionData.header.tableId {
|
|
case TsPsiIdPas:
|
|
psi.writePatSection(bw)
|
|
case TsPsiIdPms:
|
|
psi.writePmtSection(bw)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) calcPsiSectionLength() (length uint16) {
|
|
if psi.sectionData.header.tableId == TsPsiIdPas || psi.sectionData.header.tableId == TsPsiIdPms {
|
|
// Table ID extension(16 bits)+Reserved bits(2 bits)+Version number(5 bits)+Current next Indicator(1 bit)+Section number(8 bits)+Last section number(8 bits)
|
|
length += 5
|
|
}
|
|
|
|
switch psi.sectionData.header.tableId {
|
|
case TsPsiIdPas:
|
|
length += psi.calaPatSectionLength()
|
|
case TsPsiIdPms:
|
|
length += psi.calaPmtSectionLength()
|
|
}
|
|
|
|
length += 4 //crc32
|
|
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) calaPatSectionLength() (length uint16) {
|
|
length = uint16(4 * len(psi.sectionData.patData.pes))
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) calaPmtSectionLength() (length uint16) {
|
|
// Reserved bits(3 bits)+PCR PID(13 bits)+Reserved bits(4 bits)+Program info length(12 bits)
|
|
length = 4
|
|
|
|
for _, pe := range psi.sectionData.pmtData.pes {
|
|
length += 5
|
|
|
|
if len(pe.Descriptors) > 0 {
|
|
length += psi.calcDescriptorsLength(pe.Descriptors)
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) calcDescriptorsLength(ds []Descriptor) uint16 {
|
|
length := uint16(0)
|
|
for _, d := range ds {
|
|
length += 2 // tag and length
|
|
length += uint16(psi.calcDescriptorLength(d))
|
|
}
|
|
return length
|
|
}
|
|
|
|
func (psi *PsiSection) calcDescriptorLength(d Descriptor) uint8 {
|
|
if d.Length == 0 {
|
|
return 0
|
|
}
|
|
|
|
switch d.Tag {
|
|
case DescriptorTagRegistration:
|
|
return psi.calcDescriptorRegistrationLength(d.Registration)
|
|
case DescriptorTagExtension:
|
|
return psi.calcDescriptorExtensionLength(d.Extension)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
func (psi *PsiSection) calcDescriptorRegistrationLength(d DescriptorRegistration) uint8 {
|
|
return uint8(4 + len(d.AdditionalIdentificationInfo))
|
|
}
|
|
|
|
func (psi *PsiSection) calcDescriptorExtensionLength(d DescriptorExtension) uint8 {
|
|
// tag
|
|
ret := 1
|
|
if d.Unknown != nil {
|
|
ret += len(d.Unknown)
|
|
}
|
|
|
|
return uint8(ret)
|
|
}
|
|
|
|
func (psi *PsiSection) writePatSection(bw *nazabits.BitWriter) {
|
|
for _, pe := range psi.sectionData.patData.pes {
|
|
bw.WriteBits16(16, pe.pn)
|
|
bw.WriteBits8(3, 0xff)
|
|
bw.WriteBits16(13, pe.pmpid)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) writePmtSection(bw *nazabits.BitWriter) {
|
|
bw.WriteBits8(3, 0xff)
|
|
bw.WriteBits16(13, psi.sectionData.pmtData.pcrPid)
|
|
bw.WriteBits8(4, 0xff)
|
|
bw.WriteBits16(12, psi.sectionData.pmtData.programInfoLength)
|
|
|
|
for _, pe := range psi.sectionData.pmtData.pes {
|
|
bw.WriteBits8(8, pe.StreamType)
|
|
bw.WriteBits8(3, 0xff)
|
|
bw.WriteBits16(13, pe.Pid)
|
|
psi.writeDescriptorsWithLength(bw, pe.Descriptors)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (psi *PsiSection) writeDescriptorsWithLength(bw *nazabits.BitWriter, dps []Descriptor) {
|
|
bw.WriteBits8(4, 0xff)
|
|
|
|
infolen := psi.calcDescriptorsLength(dps)
|
|
bw.WriteBits16(12, infolen)
|
|
|
|
for _, dp := range dps {
|
|
psi.writeDescriptor(bw, dp)
|
|
}
|
|
}
|
|
|
|
func (psi *PsiSection) writeDescriptor(bw *nazabits.BitWriter, d Descriptor) {
|
|
length := psi.calcDescriptorLength(d)
|
|
|
|
bw.WriteBits8(8, d.Tag)
|
|
bw.WriteBits8(8, length)
|
|
|
|
switch d.Tag {
|
|
case DescriptorTagRegistration:
|
|
psi.writeDescriptorRegistration(bw, d.Registration)
|
|
case DescriptorTagExtension:
|
|
psi.writeDescriptorExtension(bw, d.Extension)
|
|
}
|
|
}
|
|
|
|
func (psi *PsiSection) writeDescriptorRegistration(bw *nazabits.BitWriter, d DescriptorRegistration) {
|
|
bw.WriteBits16(16, uint16((d.FormatIdentifier>>16)&0xFFFF))
|
|
bw.WriteBits16(16, uint16(d.FormatIdentifier&0xFFFF))
|
|
|
|
if len(d.AdditionalIdentificationInfo) > 0 {
|
|
for _, b := range d.AdditionalIdentificationInfo {
|
|
bw.WriteBits8(8, b)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (psi *PsiSection) writeDescriptorExtension(bw *nazabits.BitWriter, d DescriptorExtension) {
|
|
bw.WriteBits8(8, d.Tag)
|
|
|
|
if len(d.Unknown) > 0 {
|
|
for _, b := range d.Unknown {
|
|
bw.WriteBits8(8, b)
|
|
}
|
|
}
|
|
}
|
|
|
|
type Descriptor struct {
|
|
Length uint8
|
|
Tag uint8
|
|
Registration DescriptorRegistration
|
|
Extension DescriptorExtension
|
|
}
|
|
|
|
type DescriptorRegistration struct {
|
|
AdditionalIdentificationInfo []byte
|
|
FormatIdentifier uint32
|
|
}
|
|
|
|
type DescriptorExtension struct {
|
|
SupplementaryAudio DescriptorExtensionSupplementaryAudio
|
|
Tag uint8
|
|
Unknown []byte
|
|
}
|
|
|
|
type DescriptorExtensionSupplementaryAudio struct {
|
|
EditorialClassification uint8
|
|
HasLanguageCode bool
|
|
LanguageCode []byte
|
|
MixType bool
|
|
PrivateData []byte
|
|
}
|