使用Go调用ffprobe获取HLS时长出现exit status 1错误求助
问题修复方案
核心错误原因
exit status 1 是因为 ffprobe 执行失败,最关键的问题是请求头参数的引号错误,同时还有几处逻辑和功能缺失问题,逐一修正如下:
1. 修正请求头参数
GetDurationScript 里的 -headers 参数带了多余的双引号,exec.Command 会将每个参数作为独立项传递,不需要手动加引号,否则 ffprobe 会把带引号的字符串当作 header 的一部分,导致授权验证失败。
错误写法:
`"Authorization: YOUR_TOKEN"`
正确写法:
"Authorization: YOUR_TOKEN"
2. 修复1080p文件查找逻辑
原循环如果遍历完所有文件都没找到1080p的,会直接取最后一个文件,导致后续处理错误,需要添加判断逻辑:
found := false var targetFile *models.ProcessedFiles for _, file := range files { if file.Quality == "1080p" { targetFile = file found = true break } } if !found { return models.FileResponse{}, errors.New("1080p quality file not found") }
3. 捕获并解析ffprobe输出
原代码只是重定向输出,没有获取时长数据,需要捕获stdout并解析JSON结果:
首先定义一个结构体来解析ffprobe的输出:
type FFProbeDuration struct { Format struct { Duration string `json:"duration"` } `json:"format"` }
然后修改执行ffprobe的逻辑,捕获stdout:
var stdout bytes.Buffer var stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err = cmd.Run() if err != nil { return models.FileResponse{}, fmt.Errorf("ffprobe failed: %w, stderr: %s", err, stderr.String()) } var durationResp FFProbeDuration err = json.Unmarshal(stdout.Bytes(), &durationResp) if err != nil { return models.FileResponse{}, fmt.Errorf("failed to parse ffprobe output: %w", err) } // 这里可以将durationResp.Format.Duration转换成float64或者直接使用字符串 fmt.Printf("Video duration: %s seconds\n", durationResp.Format.Duration)
4. 移除冗余代码
原代码中调用了 os.Getwd() 但没有使用结果,直接删除即可。
完整修正后的代码
import ( "bytes" "encoding/json" "errors" "fmt" "os/exec" "your-module-path/models" "your-module-path/utils" "go.uber.org/zap" ) type FFProbeDuration struct { Format struct { Duration string `json:"duration"` } `json:"format"` } func (i *ImageGenerationService) GenerateImages(movieID int) (models.FileResponse, error) { if _, err := exec.LookPath("ffprobe"); err != nil { return models.FileResponse{}, errors.New("video.Init: ffprobe was not found in your PATH") } files, err := i.GetVideoFiles(movieID) if err != nil { i.logger.Warn("failed to get files", zap.Error(err)) return models.FileResponse{}, err } // 查找1080p文件 found := false var targetFile *models.ProcessedFiles for _, file := range files { if file.Quality == "1080p" { targetFile = file found = true break } } if !found { return models.FileResponse{}, errors.New("1080p quality file not found") } args := utils.GetDurationScript(targetFile.Filename) cmd := exec.Command("ffprobe", args...) var stdout bytes.Buffer var stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err = cmd.Run() if err != nil { return models.FileResponse{}, fmt.Errorf("ffprobe execution failed: %w, details: %s", err, stderr.String()) } // 解析时长 var durationResp FFProbeDuration err = json.Unmarshal(stdout.Bytes(), &durationResp) if err != nil { return models.FileResponse{}, fmt.Errorf("parse ffprobe output failed: %w", err) } // 这里可以根据需要处理时长,比如转换为float64 // duration, _ := strconv.ParseFloat(durationResp.Format.Duration, 64) return models.FileResponse{}, nil } func GetDurationScript(hls string) []string { return []string{ "-v", "quiet", "-show_entries", "format=duration", "-print_format", "json", "-headers", "Authorization: YOUR_TOKEN", // 去掉多余的引号 hls, } }
额外排查建议
- 确保
YOUR_TOKEN是有效的授权令牌,可以手动在终端执行ffprobe命令验证:
如果终端执行也失败,说明令牌或HLS地址有问题,和Go代码无关。ffprobe -v quiet -show_entries format=duration -print_format json -headers "Authorization: YOUR_TOKEN" https://example.com/999/1080/41509578-e299-4594-a506-cf1ff9864a1b.m3u8 - 确保ffprobe版本是最新的,旧版本可能对某些HLS格式支持不好。
内容的提问来源于stack exchange,提问作者Nurmuhammet Täjimyradow
相关产品推荐
相关产品推荐

