| 113 | } |
| 114 | |
| 115 | func PackPmt(videoCodecId, audioCodecId int) []byte { |
| 116 | ts := make([]byte, 188) |
| 117 | tsheader := []byte{0x47, 0x50, 0x01, 0x10} |
| 118 | copy(ts, tsheader) |
| 119 | |
| 120 | psi := NewPsi() |
| 121 | psi.sectionData.header.tableId = TsPsiIdPms |
| 122 | psi.sectionData.header.sectionSyntaxIndicator = 1 |
| 123 | psi.sectionData.section.tableIdExtension = 1 |
| 124 | psi.sectionData.section.currentNextIndicator = 1 |
| 125 | psi.sectionData.pmtData.pcrPid = 0x100 |
| 126 | |
| 127 | videoStreamType := StreamTypeUnknown |
| 128 | if videoCodecId == int(base.RtmpCodecIdAvc) { |
| 129 | videoStreamType = StreamTypeAvc |
| 130 | } else if videoCodecId == int(base.RtmpCodecIdHevc) { |
| 131 | videoStreamType = StreamTypeHevc |
| 132 | } |
| 133 | |
| 134 | if videoStreamType != StreamTypeUnknown { |
| 135 | psi.sectionData.pmtData.pes = append(psi.sectionData.pmtData.pes, PmtProgramElement{ |
| 136 | StreamType: videoStreamType, |
| 137 | Pid: PidVideo, |
| 138 | }) |
| 139 | } |
| 140 | |
| 141 | audioStreamType := StreamTypeUnknown |
| 142 | if audioCodecId == int(base.RtmpSoundFormatAac) { |
| 143 | audioStreamType = StreamTypeAac |
| 144 | } else if audioCodecId == int(base.RtmpSoundFormatOpus) { |
| 145 | audioStreamType = StreamTypePrivate |
| 146 | } |
| 147 | |
| 148 | if audioStreamType != StreamTypeUnknown { |
| 149 | pmtEle := PmtProgramElement{ |
| 150 | StreamType: audioStreamType, |
| 151 | Pid: PidAudio, |
| 152 | } |
| 153 | |
| 154 | if audioCodecId == int(base.RtmpSoundFormatOpus) { |
| 155 | descriptor := []Descriptor{ |
| 156 | { |
| 157 | Length: 4, |
| 158 | Tag: DescriptorTagRegistration, |
| 159 | Registration: DescriptorRegistration{ |
| 160 | FormatIdentifier: opusIdentifier, |
| 161 | }, |
| 162 | }, |
| 163 | { |
| 164 | Length: 2, |
| 165 | Tag: DescriptorTagExtension, |
| 166 | Extension: DescriptorExtension{ |
| 167 | Tag: 0x80, |
| 168 | Unknown: []uint8{0x02}, |
| 169 | }, |
| 170 | }, |
| 171 | } |
| 172 | |