老师救命呀
我想实现无缝切换输入流(远程地址和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
}
···