logo
0
0
WeChat Login

About

License: CC0-1.0

This package is targeted on unlocking libav capabilities to build dynamic pipelines for processing audio/video.

For example:

ctx, cancelFn := context.WithCancel(ctx) defer cancelFn() // input node logger.Debugf(ctx, "opening '%s' as the input...", fromURL) input, err := processor.NewInputFromURL(ctx, fromURL, secret.New(""), kernel.InputConfig{}) assert(ctx, err == nil, err) defer input.Close(ctx) inputNode := node.New(input) // output node logger.Debugf(ctx, "opening '%s' as the output...", toURL) output, err := processor.NewOutputFromURL( ctx, toURL, secret.New(""), kernel.OutputConfig{}, ) assert(ctx, err == nil, err) defer output.Close(ctx) outputNode := node.New(output) // transcoder node hwDevName := codec.HardwareDeviceName(*hwDeviceName) transcoder, err := processor.NewTranscoder( ctx, codec.NewNaiveDecoderFactory(ctx, &codec.NaiveDecoderFactoryParams{ HardwareDeviceName: hwDeviceName, }), codec.NewNaiveEncoderFactory(ctx, &codec.NaiveEncoderFactoryParams{ VideoCodec: *videoCodec, AudioCodec: codec.CodecNameCopy, HardwareDeviceType: 0, HardwareDeviceName: hwDeviceName, VideoOptions: types.DictionaryItems{{Key: "bf", Value: "0"}}.ToAstiav(), }), nil, ) assert(ctx, err == nil, err) defer transcoder.Close(ctx) logger.Debugf(ctx, "initialized a transcoder to %s (hwdev:%s)...", *videoCodec, hwDeviceName) transcodingNode := node.New(transcoder) // route nodes: input -> transcoder -> output inputNode.AddPushPacketsTo(transcodingNode) transcodingNode.AddPushPacketsTo(outputNode) logger.Debugf(ctx, "resulting pipeline: %s", inputNode.String()) logger.Debugf(ctx, "resulting pipeline (for graphviz):\n%s\n", inputNode.DotString(false)) // start errCh := make(chan node.Error, 10) observability.Go(ctx, func() { defer cancelFn() avpipeline.Serve(ctx, avpipeline.ServeConfig{ EachNode: node.ServeConfig{ FrameDrop: *frameDrop, }, }, errCh, inputNode) }) // observe statusTicker := time.NewTicker(time.Second) defer statusTicker.Stop() for { select { case <-ctx.Done(): logger.Infof(ctx, "finished") return case err, ok := <-errCh: if !ok { return } if errors.Is(err.Err, context.Canceled) { continue } if errors.Is(err.Err, io.EOF) { continue } if err.Err != nil { logger.Fatal(ctx, err) return } case <-statusTicker.C: inputStats := inputNode.GetStats() inputStatsJSON, err := json.Marshal(inputStats.FramesWrote) assert(ctx, err == nil, err) outputStats := outputNode.GetStats() outputStatsJSON, err := json.Marshal(outputStats.FramesRead) assert(ctx, err == nil, err) fmt.Printf("input:%s -> output:%s\n", inputStatsJSON, outputStatsJSON) } }

Examples

  • avd users avpipeline to implement a streaming server (as an alternative to mediamtx).
  • ffstream uses avpipeline to implement a CLI that could be used as a kick-in replacement to ffmpeg in some livestreaming use cases. It allows for dynamic change of bitrate and for enabling a passthrough mode (to disable transcoding).

AVF 轻量封装

avf 提供拉流/解码/帧回调的轻量封装,并提供通用 utils(转换、裁剪、绘制、张量)。

入口文档:

  • avf/README.md
  • avf/stream/README.md

About

这是一个基于自定义工作流自动创建的临时仓库

522.81 MiB
0 forks0 stars2 branches0 TagREADMECC0-1.0 license
Language
Go79.9%
Vue15.7%
Shell2.3%
JavaScript1.6%
Others0.5%