コード例 #1
0
ファイル: flvsak.go プロジェクト: metachord/flvsak
func permitCrop(frame flv.Frame) (isCrop bool) {
	isCrop = false
	if len(crop) <= cropIdx {
		return
	}
	start, stop := uint32(crop[cropIdx][0]), uint32(crop[cropIdx][1])
	if start <= frame.GetDts() && frame.GetDts() <= stop {
		if cropWaitKeyframe && !cropActive {
			if isKeyFrame(frame) {
				cropActive = true
				isCrop = true
			}
		} else {
			cropActive = true
			isCrop = true
		}
	} else {
		if cropWaitKeyframe && cropActive {
			if isKeyFrame(frame) {
				isCrop = false
				cropIdx++
				cropActive = false
			}
		} else {
			if cropActive {
				cropIdx++
				cropActive = false
			}
			isCrop = false
		}
	}
	return
}
コード例 #2
0
ファイル: flvsak.go プロジェクト: metachord/flvsak
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
}
コード例 #3
0
ファイル: flvsak.go プロジェクト: metachord/flvsak
func frameDump(fr flv.Frame) {
	if flvDump {
		minValid := (minDts != -1 && fr.GetDts() > uint32(minDts)) || minDts == -1
		maxValid := (maxDts != -1 && fr.GetDts() < uint32(maxDts)) || maxDts == -1
		if minValid && maxValid {
			fmt.Printf("%s\n", fr)
		}
	}
}
コード例 #4
0
ファイル: flvsak.go プロジェクト: metachord/flvsak
func writeStreamFrame(rframe flv.Frame, baseDts int) (err error) {
	if streamsWriters == nil {
		streamsWriters = make(map[uint32]*streamWriter)
	}
	stream := rframe.GetStream()
	var stWr *streamWriter
	if _, ok := streamsWriters[stream]; !ok {
		log.Printf("Write new stream %d from dts %d", stream, baseDts)
		splitFileNumber++
		stWr = new(streamWriter)
		stWr.fileName = fmt.Sprintf("n-%05d-ts-%d-s-%d.flv", splitFileNumber, baseDts, stream)
		stWr.fd, err = os.Create(stWr.fileName)
		if err != nil {
			log.Fatalf("Cannot open file %s: %s", stWr.fileName, err.Error())
		}
		stWr.writer = flv.NewWriter(stWr.fd)
		stWr.writer.WriteHeader(commonHeader)
		stWr.firstDts = baseDts
		stWr.offsetDts = rframe.GetDts()
		streamsWriters[stream] = stWr
	} else {
		stWr = streamsWriters[stream]
	}
	rframe.SetDts(rframe.GetDts() - stWr.offsetDts)
	stWr.writer.WriteFrame(rframe)
	stWr.lastDts = baseDts
	return nil
}
コード例 #5
0
ファイル: flvsak.go プロジェクト: metachord/flvsak
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
}