package media import ( "encoding/json" "ffmpeg-gui/internal/ffmpeg" "fmt" ) // StreamInfo holds information about a single stream. type StreamInfo struct { Index int `json:"index"` CodecType string `json:"codec_type"` CodecName string `json:"codec_name"` Width int `json:"width,omitempty"` Height int `json:"height,omitempty"` Duration string `json:"duration,omitempty"` BitRate string `json:"bit_rate,omitempty"` FPS string `json:"r_frame_rate,omitempty"` Language string `json:"tags>language,omitempty"` } // FormatInfo holds container format information. type FormatInfo struct { Filename string `json:"filename"` Format string `json:"format_name"` Duration string `json:"duration,omitempty"` Size string `json:"size,omitempty"` BitRate string `json:"bit_rate,omitempty"` } // MediaInfo is the top-level ffprobe result. type MediaInfo struct { Streams []StreamInfo `json:"streams"` Format FormatInfo `json:"format"` } // GetInfo runs ffprobe and returns parsed media information. func GetInfo(exec *ffmpeg.Executor, inputFile string) (*MediaInfo, error) { out, err := exec.Probe( "-v", "quiet", "-print_format", "json", "-show_format", "-show_streams", inputFile, ) if err != nil { return nil, fmt.Errorf("ffprobe: %w (output: %s)", err, out) } var info MediaInfo if err := json.Unmarshal([]byte(out), &info); err != nil { return nil, fmt.Errorf("parse ffprobe json: %w", err) } return &info, nil } // GetDurationSeconds returns the duration in seconds as a float64. func (mi *MediaInfo) GetDurationSeconds() float64 { if mi.Format.Duration == "" { return 0 } var secs float64 fmt.Sscanf(mi.Format.Duration, "%f", &secs) return secs }