我正在使用命令exec运行FFMPEG制作基于web的屏幕记录.在这里,我创建了一个startRecording函数,但我仍然对在stopRecording函数中停止命令进程感到困惑,因为命令是在startRecording函数中执行的.如何在stopRecording函数中停止已在srartRecording函数中运行的进程?

这是我的代码

//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
} 

谢谢你的预付款

推荐答案

根据 comments 的要求.

基本思想是使用global个存储器来存储活动命令.它不一定是全局的,但您需要有更大的范围,以便您的功能可以访问它.

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.Mutexsync.RWMutex来避免concurrent map writes.

所以你的commands云看起来像:

type Commands struct {
    sync.RWMutex
    items map[string]*exec.Cmd
}
// use Commands.Lock() for writing, Commands.RLock() for reading

Go相关问答推荐

Go 1.22 net/http群组路由

如何使用Promela建模语言对Golang RWLock进行建模

+在具有html/模板Golang的Base64中

使用ciph.AEAD.Seal()查看内存使用情况

如何在链接中写入链接

如何使redis池的等待超时

通过代理从golang连接到ftp

Azure golang SDK - 将 AcrPull 角色分配给 AKS 群集

用接口来模拟amqp091go的困难

如何将验证器标记添加到嵌套字段

当我的 go build 成功时,如何修复我的 docker build 失败? Dockerfile 包括 go mod 下载

自定义 Fyne 自适应网格布局

如何在 Docker 容器中使用私有存储库进行身份验证

如何将文件上传到 Google Drive,并与使用服务帐户和 Golang 的任何人共享

try 与 golang testify/suite 并行运行测试失败

关系不存在 GORM

如何使用带有Electron 表格 ID、Electron 表格名称、表格 ID 和值的 golang 在 googlesheet 中插入数据

如何使用 httputil.ReverseProxy 设置 X-Forwarded-For

空接口与泛型接口有何不同?

全局记录(across packages)