// Copyright 2019, 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 hls // 声明,本package参考了c语言实现的开源项目nginx-rtmp-module // TODO chef: // - 支持HEVC // - 检查所有的容错处理,是否会出现 // - 补充单元测试 // - 配置项 // - Server // - 超时时间 // https://developer.apple.com/documentation/http_live_streaming/example_playlists_for_http_live_streaming/incorporating_ads_into_a_playlist // https://developer.apple.com/documentation/http_live_streaming/example_playlists_for_http_live_streaming/event_playlist_construction // #EXTM3U // 固定串 // #EXT-X-VERSION:3 // 固定串 // #EXT-X-MEDIA-SEQUENCE // // #EXT-X-TARGETDURATION // 所有TS文件,最长的时长 // #EXT-X-PLAYLIST-TYPE: EVENT // #EXT-X-DISCONTINUITY // // #EXTINF: // 时长以及TS文件名 // 进来的数据称为Frame帧,188字节的封装称为TSPacket包,TS文件称为Fragment // 每个TS文件都以固定的PAT,PMT开始 var FixedFragmentHeader = []byte{ /* TS */ 0x47, 0x40, 0x00, 0x10, 0x00, /* PSI */ 0x00, 0xb0, 0x0d, 0x00, 0x01, 0xc1, 0x00, 0x00, /* PAT */ 0x00, 0x01, 0xf0, 0x01, /* CRC */ 0x2e, 0x70, 0x19, 0x05, /* stuffing 167 bytes */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* TS */ 0x47, 0x50, 0x01, 0x10, 0x00, /* PSI */ 0x02, 0xb0, 0x17, 0x00, 0x01, 0xc1, 0x00, 0x00, /* PMT */ 0xe1, 0x00, 0xf0, 0x00, 0x1b, 0xe1, 0x00, 0xf0, 0x00, /* avc epid 256 */ 0x0f, 0xe1, 0x01, 0xf0, 0x00, /* aac epid 257 */ /* CRC */ 0x2f, 0x44, 0xb9, 0x9b, /* crc for aac */ /* stuffing 157 bytes */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, } var audNal = []byte{ 0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, } // AnnexB prefix var nalStartCode = []byte{ 0x00, 0x00, 0x00, 0x01, } // TODO chef: var nalStartCode3 = []byte{ 0x00, 0x00, 0x01, } // TS Packet Header const ( syncByte uint8 = 0x47 PidPAT uint16 = 0 // ------------------------------------------ // // ------------------------------------------ AdaptationFieldControlReserved uint8 = 0 // Reserved for future use by ISO/IEC AdaptationFieldControlNo uint8 = 1 // No adaptation_field, payload only AdaptationFieldControlOnly uint8 = 2 // Adaptation_field only, no payload AdaptationFieldControlFollowed uint8 = 3 // Adaptation_field followed by payload ) // PMT const ( // ----------------------------------------------------------------------------- //
// 0x0F ISO/IEC 13818-7 Audio with ADTS transport syntax // 0x1B AVC video stream as defined in ITU-T Rec. H.264 | ISO/IEC 14496-10 Video // ----------------------------------------------------------------------------- streamTypeAAC uint8 = 0x0F streamTypeAVC uint8 = 0x1B ) // PES const ( // ----------------------------------------------------------------- //
// ----------------------------------------------------------------- streamIDAudio uint8 = 192 // 110x xxxx 0xC0 streamIDVideo uint8 = 224 // 1110 xxxx // ------------------------------ // // ------------------------------ PTSDTSFlags0 uint8 = 0 // no PTS no DTS PTSDTSFlags1 uint8 = 1 // forbidden PTSDTSFlags2 uint8 = 2 // only PTS PTSDTSFlags3 uint8 = 3 // both PTS and DTS ) const ( PidVideo uint16 = 0x100 PidAudio uint16 = 0x101 delay uint64 = 63000 // 700 ms PCR delay TODO chef: 具体作用? // TODO chef 这些在配置项中提供 negMaxfraglen = 1000 * 90 // 当前包时间戳回滚了,比当前fragment的首个时间戳还小,强制切割新的fragment,单位毫秒 * 90 maxAudioDelay uint64 = 300 // 单位毫秒 appName = "hls" ) func SplitFragment2TSPackets(content []byte) (ret [][]byte) { if len(content)%188 != 0 { return } for { if len(content) == 0 { break } ret = append(ret, content[0:188]) content = content[188:] } return }