package main import ( "encoding/hex" "flag" "github.com/q191201771/lal/pkg/avc" "github.com/q191201771/lal/pkg/httpflv" "github.com/q191201771/lal/pkg/util/bele" "github.com/q191201771/lal/pkg/util/errors" "github.com/q191201771/lal/pkg/util/log" "io" "os" ) var adtsHeader = make([]byte, 7) func captureAVC(w io.Writer, payload []byte) { // sps pps if payload[0] == 0x17 && payload[1] == 0x00 { sps, pps, err := avc.ParseAVCSeqHeader(payload) errors.PanicIfErrorOccur(err) _, _ = w.Write(avc.NaluStartCode) _, _ = w.Write(sps) _, _ = w.Write(avc.NaluStartCode) _, _ = w.Write(pps) return } // payload中可能存在多个nalu // 先跳过前面type的2字节,以及composition time的3字节 for i := 5; i != len(payload); { naluLen := int(bele.BEUint32(payload[i:])) i += 4 //naluUintType := payload[i] & 0x1f //log.Debugf("naluLen:%d t:%d %s\n", naluLen, naluUintType, avc.NaluUintTypeMapping[naluUintType]) _, _ = w.Write(avc.NaluStartCode) _, _ = w.Write(payload[i:i+naluLen]) i += naluLen break } return } // TODO chef: mv to pkg func captureAAC(w io.Writer, payload []byte) { soundFormat := payload[0] >> 4 soundRate := (payload[0] >> 2) & 0x03 soundSize := (payload[0] >> 1) & 0x01 soundType := payload[0] & 0x01 if payload[1] == 0 { audioObjectType := (payload[2] >> 3) & 0x1f // 5bit 编码结构类型 samplingFrequencyIndex := ((payload[2] & 0x07) << 1) | (payload[3] >> 7) // 4bit 音频采样率索引值 channelConfig := (payload[3] >> 3) & 0x0f // 4bit 音频输出声道 // syncword 12bit // ID 1bit // layer 2 // protection_absent 1bit // profile 2bit // sampling_frequency_index 4bit // private_bit 1bit // channel_configuration 3bit // origin_copy 1bit // home 1bit adtsHeader[0] = 0xff // 8bit syncword 高8bit adtsHeader[1] = 0xf0 // 4bit syncword 低4bit // 1bit ID 0 for MPEG-4, 1 for MPEG-2 // 2bit layer 0 adtsHeader[1] |= 1 // 1bit protection absent adtsHeader[2] = (audioObjectType - 1) << 6 log.Debugf(hex.Dump(payload[:4])) log.Debugf("%d %d %d %d\n", soundFormat, soundRate, soundSize, soundType) log.Debugf("%d %d %d", audioObjectType, samplingFrequencyIndex, channelConfig) } } func main() { var err error flvFileName, aacFileName, avcFileName := parseFlag() var ffr httpflv.FlvFileReader err = ffr.Open(flvFileName) errors.PanicIfErrorOccur(err) defer ffr.Dispose() log.Infof("open flv file succ.") afp, err := os.Create(aacFileName) errors.PanicIfErrorOccur(err) defer afp.Close() log.Infof("open es aac file succ.") vfp, err := os.Create(avcFileName) errors.PanicIfErrorOccur(err) defer vfp.Close() log.Infof("open es h264 file succ.") _, err = ffr.ReadFlvHeader() errors.PanicIfErrorOccur(err) for { tag, err := ffr.ReadTag() if err == io.EOF { log.Infof("EOF.") break } errors.PanicIfErrorOccur(err) payload := tag.Payload() switch tag.Header.T { case httpflv.TagTypeAudio: captureAAC(afp, payload) case httpflv.TagTypeVideo: captureAVC(vfp, payload) } } } func parseFlag() (string, string, string) { flv := flag.String("i", "", "specify flv file") aac := flag.String("a", "", "specify es aac file") avc := flag.String("v", "", "specify es h264 file") flag.Parse() if *flv == "" || *avc == "" || *aac == "" { flag.Usage() os.Exit(1) } return *flv, *aac, *avc }