请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

ffmpeg filter 实时切换输入流的问题

老师救命呀

我想实现无缝切换输入流(远程地址和rtmp流),添加一路和减少一路

我前面使用的是重构滤镜图,重新新建一个滤镜图,但是这种方式,会丢帧,在一个会在切换的时候,帧率波动比较大,还容易卡顿

现在修改为使用修改滤镜图的方式
但是我在修改滤镜图的时候报错了,
最后面的代码中 f true {}位置
使用avfilter_free,取消overlay滤镜,然后重新新建一个overlay,然后使用avfilter_link代替上去

但是在使用avfilter_graph_config()的时候,
报错
[AVFilterGraph @ 0x10fda00] query_formats: 11 queried, 10 merged, 0 already done, 0 delayed[setpts0 @ 0x1143500] [IMGUTILS @ 0x7ffd08cf9680] Picture size 0x0 is invalid

然后我在graph_desc := C.avfilter_graph_dump(graph, nil) 这一行之前添加了下面的代码

(*(**ol.Streams[0].SetptsCtx).outputs).w = 1080
		(*(**ol.Streams[0].SetptsCtx).outputs).h = 1920

		(*(**ol.Streams[0].SetptsCtx).outputs).time_base.den = 30
		(*(**ol.Streams[0].SetptsCtx).outputs).time_base.num = 1

		(*(**ol.Streams[0].SetptsCtx).outputs).frame_rate.den = 30
		(*(**ol.Streams[0].SetptsCtx).outputs).frame_rate.num = 1

		(*(**ol.Streams[1].SetptsCtx).outputs).w = 480
		(*(**ol.Streams[1].SetptsCtx).outputs).h = 480

		(*(**ol.Streams[1].SetptsCtx).outputs).time_base.den = 30
		(*(**ol.Streams[1].SetptsCtx).outputs).time_base.num = 1

		(*(**ol.Streams[1].SetptsCtx).outputs).frame_rate.den = 30
		(*(**ol.Streams[1].SetptsCtx).outputs).frame_rate.num = 1

		(*(**ol.Streams[1].OverlayCtx).outputs).w = 1080
		(*(**ol.Streams[1].OverlayCtx).outputs).h = 1920

		(*(**ol.Streams[1].OverlayCtx).outputs).time_base.den = 30
		(*(**ol.Streams[1].OverlayCtx).outputs).time_base.num = 1

		(*(**ol.Streams[1].OverlayCtx).outputs).frame_rate.den = 30
		(*(**ol.Streams[1].OverlayCtx).outputs).frame_rate.num = 1
                // ol.OscaleCtx,这个滤镜连接的是buffersink滤镜
		(*(**ol.OscaleCtx).outputs).w = 1080
		(*(**ol.OscaleCtx).outputs).h = 1920

		(*(**ol.OscaleCtx).outputs).time_base.den = 30
		(*(**ol.OscaleCtx).outputs).time_base.num = 1

		(*(**ol.OscaleCtx).outputs).frame_rate.den = 30
		(*(**ol.OscaleCtx).outputs).frame_rate.num = 1

这个时候avfilter_graph_config()不报错了,能运行过去了,
但是另外的协程在运行到这一行的时候

ret := C.av_buffersink_get_frame(*onLive.BufsinkCtx, onLive.FilterFrame)

读取buffersink的时候报错段错误

SIGSEGV: segmentation violation
PC=0x7fb36f208292 m=3 sigcode=1 addr=0x38
signal arrived during cgo execution

goroutine 35 gp=0xc000102700 m=3 mp=0xc00005f008 [syscall]:
runtime.cgocall(0x904f7f, 0xc0001c5410)
	/usr/local/go/src/runtime/cgocall.go:157 +0x4b fp=0xc0001c53e8 sp=0xc0001c53b0 pc=0x409deb
main._Cfunc_av_buffersink_get_frame(0x176ee40, 0x7fb3180f38c0)

下面是我的代码

···
func (ol *OneLive) Filter(noChange, toDelete []int) error {
fmt.Println(time.Now().String(), “重置滤镜开始=================================”)

graph := C.avfilter_graph_alloc()
if graph == nil {
	return fmt.Errorf("avfilter_graph_alloc() error")
}
defer func() {
	if *ol.Graph != nil {
		C.avfilter_graph_free(ol.Graph)
	}
	*ol.Graph = graph

}()

if ret := C.avfilter_graph_create_filter(ol.BufsinkCtx, ol.Bufsink, C.CString("out"), nil, nil, graph); ret < 0 {
	return fmt.Errorf("failed to create buffer sink filter context! avfilter_graph_create_filter error:%s", avErr2str(ret))
}

C.my_av_opt_set_int_list(ol.BufsinkCtx)
//}
//540:960:270:480
cropStr := C.CString("crop")
defer C.free(unsafe.Pointer(cropStr))
fpsStr := C.CString("fps")
defer C.free(unsafe.Pointer(fpsStr))
scaleStr := C.CString("scale")
defer C.free(unsafe.Pointer(scaleStr))
setpt := C.CString("setpts")
defer C.free(unsafe.Pointer(setpt))
startPts := fmt.Sprintf("PTS-STARTPTS+%v", ol.LatestPTS+1)
setptsArgs := C.CString(startPts)
defer C.free(unsafe.Pointer(setptsArgs))
for index := range ol.Streams {
	if ol.Streams[index] == nil {
		continue
	}

	//if isArray(noChange, index) || isArray(toDelete, index) {
	//	continue
	//}

	bufCtx := ol.Streams[index].BufCtx
	bufSrc := ol.Streams[index].BufSRC
	name := C.CString(fmt.Sprintf("in%d", index))
	args := ol.Streams[index].Args
	if ret := C.avfilter_graph_create_filter(bufCtx,
		bufSrc,
		name,
		args,
		nil,
		graph); ret < 0 {
		return fmt.Errorf("failed to create buffer filter context! error:%s", avErr2str(ret))
	}
	// Add setpts filter to reset the PTS
	var setptsCtx *C.AVFilterContext
	setpts := C.avfilter_get_by_name(setpt)

	setptsp2 := C.CString(fmt.Sprintf("setpts%d", index))
	if ret := C.avfilter_graph_create_filter(&setptsCtx, setpts, setptsp2, setptsArgs, nil, graph); ret < 0 {
		C.free(unsafe.Pointer(setptsp2))
		return fmt.Errorf("failed to create setpts filter context! error:%s", avErr2str(ret))
	}
	C.free(unsafe.Pointer(setptsp2))

	lastCtx := *bufCtx
	if ol.Streams[index].CropWidth != nil && ol.Streams[index].CropHeight != nil && ol.Streams[index].CropX != nil && ol.Streams[index].CropY != nil && *ol.Streams[index].CropWidth > 0 && *ol.Streams[index].CropHeight > 0 {
		// crop
		var cropCtx *C.AVFilterContext
		// 宽 高 坐标
		cropParam := fmt.Sprintf("%v:%v:%v:%v", *ol.Streams[index].CropWidth, *ol.Streams[index].CropHeight, *ol.Streams[index].CropX, *ol.Streams[index].CropY)
		if ret := C.avfilter_graph_create_filter(&cropCtx, C.avfilter_get_by_name(cropStr), C.CString(fmt.Sprintf("crop%d", index)), C.CString(cropParam), nil, graph); ret < 0 {
			return fmt.Errorf("failed to create scale filter context! error:%s", avErr2str(ret))
		}
		// 创建 scale 过滤器
		if ret := C.avfilter_link(lastCtx, 0, cropCtx, 0); ret < 0 {
			return fmt.Errorf("failed to link buffer to setpts! error:%s", avErr2str(ret))
		}
		lastCtx = cropCtx
	}

	// scale
	var scaleCtx *C.AVFilterContext
	if ret := C.avfilter_graph_create_filter(&scaleCtx, C.avfilter_get_by_name(scaleStr), C.CString(fmt.Sprintf("scale%d", index)), C.CString(fmt.Sprintf("width=%v:height=%v", *ol.Streams[index].ScaleWidth, *ol.Streams[index].ScaleHeight)), nil, graph); ret < 0 {
		return fmt.Errorf("failed to create scale filter context! error:%s", avErr2str(ret))
	}

	// 创建 scale 过滤器
	if ret := C.avfilter_link(lastCtx, 0, scaleCtx, 0); ret < 0 {
		return fmt.Errorf("failed to link buffer to setpts! error:%s", avErr2str(ret))
	}
	lastCtx = scaleCtx

	// fps
	var fpsCtx *C.AVFilterContext
	fpsParam := fmt.Sprintf("fps=%v", 30)
	if ret := C.avfilter_graph_create_filter(&fpsCtx, C.avfilter_get_by_name(fpsStr), C.CString(fmt.Sprintf("fps%d", index)), C.CString(fpsParam), nil, graph); ret < 0 {
		return fmt.Errorf("failed to create scale filter context! error:%s", avErr2str(ret))
	}
	// 创建 fps 过滤器
	if ret := C.avfilter_link(lastCtx, 0, fpsCtx, 0); ret < 0 {
		return fmt.Errorf("failed to link buffer to setpts! error:%s", avErr2str(ret))
	}
	lastCtx = fpsCtx
	//setpts
	if ret := C.avfilter_link(lastCtx, 0, setptsCtx, 0); ret < 0 {
		return fmt.Errorf("failed to link buffer to setpts! error:%s", avErr2str(ret))
	}

	ol.Streams[index].BufCtx = bufCtx
	ol.Streams[index].SetptsCtx = &setptsCtx
	//ol.Streams[index].BufCtx = bufCtx
}

var overlayCtx *C.AVFilterContext
var prevOverlayCtx *C.AVFilterContext
overlayStr := C.CString("overlay")
defer C.free(unsafe.Pointer(overlayStr))
overlay := C.avfilter_get_by_name(overlayStr)

for index := 1; index < len(ol.Streams); index++ {
	if ol.Streams[index] == nil {
		continue
	}

	name := C.CString(fmt.Sprintf("overlay%d", index))
	args := C.CString(fmt.Sprintf("x=%f:y=%f:eof_action=pass", *ol.Streams[index].X, *ol.Streams[index].Y))

	if ret := C.avfilter_graph_create_filter(&overlayCtx, overlay, name, args, nil, graph); ret < 0 {
		C.free(unsafe.Pointer(name))
		C.free(unsafe.Pointer(args))
		return fmt.Errorf("failed to create overlay filter context! error:%s", avErr2str(ret))
	}
	C.free(unsafe.Pointer(name))
	C.free(unsafe.Pointer(args))

	if prevOverlayCtx == nil {
		if ret := C.avfilter_link(*ol.Streams[0].SetptsCtx, 0, overlayCtx, 0); ret < 0 {
			return fmt.Errorf("first failed to link buffer to overlay! error:%s", avErr2str(ret))
		}
	} else {
		if ret := C.avfilter_link(prevOverlayCtx, 0, overlayCtx, 0); ret < 0 {
			return fmt.Errorf("failed to link previous overlay to new overlay! error:%s", avErr2str(ret))
		}
	}

	if ret := C.avfilter_link(*ol.Streams[index].SetptsCtx, 0, overlayCtx, 1); ret < 0 {
		return fmt.Errorf("failed to link buffer to overlay! error:%s", avErr2str(ret))
	}
	//ol.Streams[index].OverlayCtx = &overlayCtx
	prevOverlayCtx = overlayCtx
}

//*(*ol.BufsinkCtx).inputs = nil
if prevOverlayCtx != nil {
	if ret := C.avfilter_link(prevOverlayCtx, 0, *ol.BufsinkCtx, 0); ret < 0 {
		return fmt.Errorf("failed to link final overlay to buffer sink! error:%s", avErr2str(ret))
	}
} else {
	if ret := C.avfilter_link(*ol.Streams[0].SetptsCtx, 0, *ol.BufsinkCtx, 0); ret < 0 {
		return fmt.Errorf("failed to link buffer to buffer sink! error:%s", avErr2str(ret))
	}
}

if ret := C.avfilter_graph_config(graph, nil); ret < 0 {
	return fmt.Errorf("failed to config graph ,avfilter_graph_config() error:%s", avErr2str(ret))
}
// 想着重新更新下滤镜图,
if true {
	C.avfilter_free(*ol.Streams[1].OverlayCtx)
	*ol.Streams[1].OverlayCtx = nil

	name := C.CString(fmt.Sprintf("overlay%d", 1))
	args := C.CString(fmt.Sprintf("x=%f:y=%f", *ol.Streams[1].X, *ol.Streams[1].Y))

	if ret := C.avfilter_graph_create_filter(&overlayCtx, overlay, name, args, nil, graph); ret < 0 {
		C.free(unsafe.Pointer(name))
		C.free(unsafe.Pointer(args))
		return fmt.Errorf("failed to create overlay filter context! error:%s", avErr2str(ret))
	}
	C.free(unsafe.Pointer(name))
	C.free(unsafe.Pointer(args))

	if ret := C.avfilter_link(*ol.Streams[0].SetptsCtx, 0, overlayCtx, 0); ret < 0 {
		return fmt.Errorf("first failed to link buffer to overlay! error:%s", avErr2str(ret))
	}

	if ret := C.avfilter_link(*ol.Streams[1].SetptsCtx, 0, overlayCtx, 1); ret < 0 {
		return fmt.Errorf("failed to link previous overlay to new overlay! error:%s", avErr2str(ret))
	}

	if ret := C.avfilter_link(overlayCtx, 0, *ol.OscaleCtx, 0); ret < 0 {
		return fmt.Errorf("failed to link final overlay to buffer sink! error:%s", avErr2str(ret))
	}
	*ol.Streams[1].OverlayCtx = overlayCtx

	graph_desc := C.avfilter_graph_dump(graph, nil)
	fmt.Println(C.GoString(graph_desc), "2222222222222")
	defer C.free(unsafe.Pointer(graph_desc))
	if ret := C.avfilter_graph_config(graph, nil); ret < 0 {

		return fmt.Errorf("failed to config graph ,avfilter_graph_config() error:%s", avErr2str(ret))
	}
}
fmt.Println(time.Now().String(), "重置滤镜完成=================================")
return nil

}
···

正在回答 回答被采纳积分+3

1回答

李超 2024-08-26 20:25:49

直接切线路就好了,为啥要用滤镜呢?

0 回复 有任何疑惑可以回复我~
  • 提问者 博楠 #1
    我们想实现叠加的效果,切线路是指,滤镜不动,往buffer里面添加的数据修改为新的吗?
    
    还是只修改需要动的那个滤镜呢,
    我没有懂这个怎么切线路
    回复 有任何疑惑可以回复我~ 2024-08-26 20:41:50
  • 提问者 博楠 #2
    老师我是刚刚接触不久,网上搜索也没有搜索到,不知道怎么切呢,老师,您帮忙给解释解释呗
    回复 有任何疑惑可以回复我~ 2024-08-26 20:49:26
  • 李超 回复 提问者 博楠 #3
    我不清楚你们的产品形态是啥,像腾讯视频,如果一个线路不好,切到另一个线路,直接切就好了,需要注意的是切之前要保证从前一个GO P开始就好了。从你后来的描述来看,你们不是这样简单的切流?
    回复 有任何疑惑可以回复我~ 2024-08-26 20:49:37
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信