func permitSkip(frame flv.Frame) (isSkip bool) { if frame.GetType() == flv.TAG_TYPE_META { metaBody := frame.GetBody() buf := bytes.NewReader(*metaBody) dec := amf0.NewDecoder(buf) evName, err := dec.Decode() if err == nil { switch evName { case amf0.StringType("onMetaData"): md, err := dec.Decode() if err == nil { var ea map[amf0.StringType]interface{} switch md := md.(type) { case *amf0.EcmaArrayType: ea = *md case *amf0.ObjectType: ea = *md } for skipK, skipV := range skipMeta { if s, ok := ea[amf0.StringType(skipK)]; ok { for _, t := range skipV { if amf0.StringType(t) == s { return true } } } } } } } } return false }
func writeFrames(frReader *flv.FlvReader, frW map[flv.TagType]*flv.FlvWriter, offset int) (outOffset int) { lastTs := make(map[flv.TagType]map[uint32]uint32) lastTsDiff := make(map[flv.TagType]map[uint32]uint32) shiftTs := make(map[flv.TagType]map[uint32]uint32) for _, c := range []flv.TagType{flv.TAG_TYPE_VIDEO, flv.TAG_TYPE_AUDIO, flv.TAG_TYPE_META} { lastTs[c] = make(map[uint32]uint32) lastTsDiff[c] = make(map[uint32]uint32) shiftTs[c] = make(map[uint32]uint32) } updateDts := func(cframe flv.Frame) (newDts uint32) { c := cframe.GetType() s := cframe.GetStream() d := cframe.GetDts() if lastTs[c][s] > d { warnTs(lastTs[c][s], s, d) if fixDts { newDts := lastTs[c][s] + lastTsDiff[c][s] shiftTs[c][s] = newDts - d d += shiftTs[c][s] } } d = uint32(int(float64(d)*scaleDts) + offset) lastTsDiff[c][s] = d - lastTs[c][s] lastTs[c][s] = d return d } var lastInTs uint32 = 0 var compensateTs uint32 = 0 for { var rframe flv.Frame var err error var skipBytes int rframe, rerr := frReader.ReadFrame() switch { case rerr != nil && !readRecover: log.Fatal(rerr) case rerr != nil && rerr.IsRecoverable(): rframe, err, skipBytes = frReader.Recover(rerr, maxScanSize) if err != nil { log.Fatalf("recovery error: %s", err) } log.Printf("recover: got fine frame after %d bytes", skipBytes) continue } if rframe != nil { // if rframe.GetType() == flv.TAG_TYPE_META { // metaBody := rframe.GetBody() // buf := bytes.NewReader(*metaBody) // dec := amf0.NewDecoder(buf) // _, err := dec.Decode() // if err != nil { // log.Printf("Bad metadata at DTS %d", rframe.GetDts()) // continue // } // } isCrop := permitCrop(rframe) isSkip := permitSkip(rframe) isSplitStream := splitStreams && rframe.GetStream() != 0 && rframe.GetType() != flv.TAG_TYPE_META if (streams[rframe.GetType()] != -1 && rframe.GetStream() != uint32(streams[rframe.GetType()])) || isCrop || isSkip || isSplitStream { if compensateDts || isCrop { compensateTs += (rframe.GetDts() - lastInTs) } lastInTs = rframe.GetDts() if splitStreams { err = writeStreamFrame(rframe, outOffset) if err != nil { log.Fatal(err) } } continue } checkSplitWriters(outOffset) lastInTs = rframe.GetDts() newDts := updateDts(rframe) - compensateTs if rframe.GetStream() == 0 { outOffset = int(newDts) } rframe.SetDts(newDts) err = frW[rframe.GetType()].WriteFrame(rframe) if err != nil { log.Fatal(err) } } else { break } } return }