英文:
How to kill command Exec in difference Function in Golang
问题
我正在制作一个基于Web的屏幕录制程序,使用命令exec来运行FFMPEG。我创建了一个startRecording函数,但是我对于在stopRecording函数中停止命令进程感到困惑,因为命令是在startRecording函数中执行的。如何在stopRecording函数中停止已经在startRecording函数中运行的进程呢?
这是我的代码:
// 创建房间/开始录制的处理程序
func RoomCreate(c *fiber.Ctx) error {
fileName := "out.mp4"
fmt.Println(fileName)
if len(os.Args) > 1 {
fileName = os.Args[1]
}
errCh := make(chan error, 2)
ctx, cancelFn := context.WithCancel(context.Background())
// 调用startRecording函数
go func() { errCh <- startRecording(ctx, fileName) }()
go func() {
errCh <- nil
}()
err := <-errCh
cancelFn()
if err != nil && err != context.Canceled {
log.Fatalf("Execution failed: %v", err)
}
return c.Redirect(fmt.Sprintf("/room/%s", guuid.New().String()))
}
// 运行FFMPEG命令的函数
func startRecording(ctx context.Context, fileName string) error {
ctx, cancelFn := context.WithCancel(ctx)
defer cancelFn()
// 构建ffmpeg命令
ffmpeg := exec.Command("ffmpeg",
"-f", "gdigrab",
"-framerate", "30",
"-i", "desktop",
"-f", "mp4",
fileName,
)
// 用于发送数据的标准输入
stdin, err := ffmpeg.StdinPipe()
if err != nil {
return err
}
defer stdin.Close()
// 在后台运行命令
errCh := make(chan error, 1)
go func() {
fmt.Printf("Executing: %v\n", strings.Join(ffmpeg.Args, " "))
if err := ffmpeg.Run(); err != nil {
return
}
errCh <- err
}()
// 只需开始发送一堆帧
for {
// 检查是否完成,否则继续
select {
case <-ctx.Done():
return ctx.Err()
case err := <-errCh:
return err
default:
}
}
}
// 在这里停止录制的函数
func stopRecording(ctx context.Context) error {
// 在这里停止录制的代码
}
提前感谢。
英文:
i'm making screen record web based using command exec to run FFMPEG. here I created a startRecording function but I am still confused about stopping the command process in the stopRecording function, because the command is executed in the startRecording function. How to stop a process that is already running in the srartRecording function in the stopRecording function?
here my code
//Handler to create room/start record
func RoomCreate(c *fiber.Ctx) error {
fileName := "out.mp4"
fmt.Println(fileName)
if len(os.Args) > 1 {
fileName = os.Args[1]
}
errCh := make(chan error, 2)
ctx, cancelFn := context.WithCancel(context.Background())
// Call to function startRecording
go func() { errCh <- startRecording(ctx, fileName) }()
go func() {
errCh <- nil
}()
err := <-errCh
cancelFn()
if err != nil && err != context.Canceled {
log.Fatalf("Execution failed: %v", err)
}
return c.Redirect(fmt.Sprintf("/room/%s", guuid.New().String()))
}
//Function to run command FFMPEG
func startRecording(ctx context.Context, fileName string) error {
ctx, cancelFn := context.WithCancel(ctx)
defer cancelFn()
// Build ffmpeg
ffmpeg := exec.Command("ffmpeg",
"-f", "gdigrab",
"-framerate", "30",
"-i", "desktop",
"-f", "mp4",
fileName,
)
// Stdin for sending data
stdin, err := ffmpeg.StdinPipe()
if err != nil {
return err
}
//var buf bytes.Buffer
defer stdin.Close()
// Run it in the background
errCh := make(chan error, 1)
go func() {
fmt.Printf("Executing: %v\n", strings.Join(ffmpeg.Args, " "))
if err := ffmpeg.Run(); err != nil {
return
}
//fmt.Printf("FFMPEG output:\n%v\n", string(out))
errCh <- err
}()
// Just start sending a bunch of frames
for {
// Check if we're done, otherwise go again
select {
case <-ctx.Done():
return ctx.Err()
case err := <-errCh:
return err
default:
}
}
}
//Here function to stop Recording
func stopRecording(ctx context.Context) error {
//Code stop recording in here
}
Thanks for advance
答案1
得分: 1
根据评论的要求,基本思路是使用全局存储来存储活动命令。它不一定要是全局的,但你需要有更大的范围,以便你的函数可以访问它。
var commands = map[string]*exec.Cmd{}
func startRecording(fileName string) error {
ffmpeg := exec.Command("ffmpeg",
"-f", "gdigrab",
"-framerate", "30",
"-i", "desktop",
"-f", "mp4",
fileName,
)
commands[fileName] = ffmpeg
...
}
func stopRecording(fileName string) error {
cmd, ok := commands[fileName]
if !ok {
return errors.New("command not found")
}
defer func() {
delete(commands, fileName)
}()
return cmd.Process.Kill()
}
你可能想要使用sync.Mutex或sync.RWMutex来避免并发的 map 写入。
所以你的 commands
可以像这样:
type Commands struct {
sync.RWMutex
items map[string]*exec.Cmd
}
// 使用 Commands.Lock() 进行写入,Commands.RLock() 进行读取
英文:
As requested from comments.
The basic idea is to use global storage to store your active commands. It doesn't necessarily be global but you need to have bigger scope so that your functions can access it.
var commands = map[string]*exec.Cmd{}
func startRecording(fileName string) error {
ffmpeg := exec.Command("ffmpeg",
"-f", "gdigrab",
"-framerate", "30",
"-i", "desktop",
"-f", "mp4",
fileName,
)
commands[fileName] = ffmpeg
...
}
func stopRecording(fileName string) error {
cmd, ok := commands[fileName]
if !ok {
return errors.New("command not found")
}
defer func() {
delete(commands, fileName)
}()
return cmd.Process.Kill()
}
You probably want to use sync.Mutex or sync.RWMutex to avoid concurrent map writes.
So your commands
cloud look like:
type Commands struct {
sync.RWMutex
items map[string]*exec.Cmd
}
// use Commands.Lock() for writing, Commands.RLock() for reading
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论