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.
lal/app/flvfile2es/flvfile2es.go

131 lines
3.4 KiB
Go

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}