【问题标题】:How to divide a time duration in half如何将持续时间分成两半
【发布时间】:2020-01-03 10:23:05
【问题描述】:

我试图找到视频的中点,换句话说,将总长度除以2ffmpegHOURS:MM:SS.MICROSECONDS 格式给出时间,所以忽略微秒,我怎么能得到中间点?我尝试将每个数字 (hours/minutes/seconds) 除以 2,但在 0:01:00 的情况下会失败。

【问题讨论】:

  • 你能显示一些代码吗?你试过什么?
  • @mkopriva 在我正确格式化我的答案之前你抓住了我 :)
  • @KellyFlet:您应该在发布之前正确格式化您的问题。
  • 反对票是怎么回事?我的问题很清楚,@icza 可以在没有任何进一步说明的情况下提供清晰简洁的答案。我为自己的问题提供了答案,所以这并不是说我没有尝试任何事情(通常是抱怨),并且认为我不会用我尝试过的所有不同的事情来混淆这个问题;相反,保持简单。当然,我的回答不是最简洁的,这就是为什么社区在这里提供更好的答案。

标签: go ffmpeg


【解决方案1】:

如果我们使用time 包提供的解析和格式化逻辑,这会更简单(甚至可能更快)。

func getDividedTime(times string, n int) (string, error) {
    t, err := time.Parse("15:04:05.000000", times)
    if err != nil {
        return "", err
    }
    d := t.Sub(time.Time{}) / time.Duration(n)
    return time.Time{}.Add(d).Format("15:04:05"), nil
}

Go Playground 上试试。此解决方案的弱点在于它“拒绝”具有hours > 23 的输入。

【讨论】:

  • 我也首先想到了这一点,但我不希望在计时器实现中设置 24 小时的上限。检查this一出!
【解决方案2】:

避免解析 ffmpeg 的 stderr 输出以获取持续时间(这就是我假设您正在做的事情):它不适用于机器解析并且容易损坏。这就是 ffprobe 的用途,您无需执行额外的处理来隔离持续时间。

您可以使用ffprobe 来获得以秒为单位的持续时间,这更容易划分:

ffprobe -v error -show_entries format=duration -of csv=p=0 input.mp4

示例结果:

48.012000

然后使用您喜欢的函数或工具除以 2。(Example using bc in a Bash script.)

如果您需要HOURS:MM:SS.MICROSECONDS,请添加-sexagesimal 选项。

【讨论】:

    【解决方案3】:

    使用Duration 而不是Time 的更简单的解决方案。它允许解析小时> 24。在处理计时器或在您的情况下,视频持续时间时通常需要这样做!

    func getDividedTime(st string, div int) string {
        var h, m, s int
        fmt.Sscanf(st, "%d:%d:%d", &h, &m, &s)
        seconds := (h*60*60 + m*60 + s) / div
        d := time.Duration(int64(seconds) * int64(1e9))
        hh, mm, ss := int(d.Hours()), int(d.Minutes()), int(d.Seconds())
        return fmt.Sprintf("%d:%02d:%02d", hh, mm-(hh*60), ss-(mm*60))
    }
    

    Go Playground 试试吧!随意检查fmt.Sscanf()返回的无效输入错误!

    【讨论】:

      【解决方案4】:

      基本上,您想要:

      1. 将所有内容转换为秒
      2. 除以 2
      3. 转换回时:分:秒

      (并对ffmpeg 进行一些格式化)。 另请注意,此答案可以概括为除以n,而不仅仅是减半。

      import (
          "fmt"
          "strconv"
          "strings"
      )
      
      // ffmpeg uses the format HOURS:MM:SS.MICROSECONDS
      func getDividedTime(time string, n int) string {
          times := strings.Split(time, ":")
      
          // get rid of microseconds
          times[2] = strings.Split(times[2], ".")[0]
      
          // conversions
          minutesToSeconds := 60
          hoursToSeconds := 60 * minutesToSeconds
      
          // convert everything to seconds
          seconds, _ := strconv.Atoi(times[2])
          minutes, _ := strconv.Atoi(times[1])
          hours, _ := strconv.Atoi(times[0])
      
          secMinutes := minutes * minutesToSeconds
          secHours := hours * hoursToSeconds
      
          totalSeconds := seconds + secHours + secMinutes
          totalSeconds /= n
      
          // update time and grab seconds
          newSeconds := totalSeconds % 60
          totalSeconds /= 60
      
          // update time and grab minutes
          newMinutes := totalSeconds % 60
          totalSeconds /= 60
      
          newHours := totalSeconds % 3600
      
          times[0] = strconv.Itoa(newHours)
          times[1] = strconv.Itoa(newMinutes)
          times[2] = strconv.Itoa(newSeconds)
      
          // zero padding for seconds and minutes (not hours)
          if newMinutes < 10 {
              times[1] = "0" + times[1]
          }
          if newSeconds < 10 {
              times[2] = "0" + times[2]
          }
      
          dividedTime := strings.Join(times[:], ":")
          return dividedTime 
      }
      
      func main() {
          // create some tests
          tables := []struct {
              inputTime   string
              correctTime string
          }{
              {"0:11:28.956000", "0:05:44"},
              {"1:00:00.111999", "0:30:00"},
              {"1:15:00.111999", "0:37:30"},
              {"1:45:00.111999", "0:52:30"},
              {"0:59:00.000000", "0:29:30"},
              {"2:04:22.123151", "1:02:11"},
              {"0:00:00.000000", "0:00:00"},
              {"0:00:03.000000", "0:00:01"},
              {"0:00:04.000000", "0:00:02"},
              {"0:20:00.000000", "0:10:00"},
              {"0:02:00.000000", "0:01:00"},
              {"99:00:00.000000", "49:30:00"},
          }
      
          // ensure output matches truth values
          for _, table := range tables {
              output := getDividedTime(table.inputTime, 2) // cut time in half
              if output != table.correctTime {
                  fmt.Printf("failure: expected: %s, got: %s\n", table.correctTime, output)
              }
          }
      }
      

      【讨论】:

      • ffmpeg 仅在某些显示字段中使用格式 HOURS:MM:SS.MICROSECONDS -->。它几乎在每个函数中都接受小数秒。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-12
      • 2013-05-25
      • 2013-12-06
      • 2012-05-26
      • 1970-01-01
      • 2015-05-08
      相关资源
      最近更新 更多