3d0c / gmf

Go Media Framework
MIT License
885 stars 170 forks source link

SeekFrameAt doesn't seem to work #129

Closed ccaum closed 4 years ago

ccaum commented 4 years ago

I'm attempting to use SeekFrameAt to go back to grab the last 10 seconds of a mp4 video file. The video is 60 seconds long, so I need to go back to the 50th second of the video. I'm using the code below, but SeekFrameAt doesn't seem to have any affect on the position of input ctx. I've also tried using SeekFile() with the same results. Am I missing something?

Below is the code I'm using to prove things out. If I take the SeekFrameAt() call out, the start packet is always the same.

package main

import(
  "log"
  "github.com/3d0c/gmf"
)

func main() {  
  fileCtx, err := gmf.NewInputCtx("video.mp4")
  if err != nil {
    log.Print("Unable to load recording file while generating video clip: ", err.Error())
  }

  videoStream, _ := fileCtx.GetBestStream(gmf.AVMEDIA_TYPE_VIDEO)

  //Go back 10 seconds from the end of the recording
  timeStamp := int64(fileCtx.Duration() - 10)
  log.Print("Seeking second ", timeStamp)

  seekErr := fileCtx.SeekFrameAt(timeStamp, videoStream.Index())
  if seekErr != nil {
    log.Print("Could not retrieve frame from 10 seconds ago: ", err)
    return
  }

  log.Print("FmtCtx Position: ", fileCtx.Position())
  packet, err := fileCtx.GetNextPacket()
  if err != nil {
    log.Print("Error getting frame for clip: ", err.Error())
  }
  log.Print("Start position: ", packet.Pos())
  log.Print("Start pts: ", packet.Pts())
}

Output:

2020/06/14 17:30:37 Seeking second 50
2020/06/14 17:30:37 FmtCtx Position: 32816
2020/06/14 17:30:37 Start position: 48
2020/06/14 17:30:37 Start pts: 23228094600
ccaum commented 4 years ago

I've also tried it with SeekFile with the same results. Below is a section of the code I'm using for that..

  timeStamp := int64(fileCtx.Duration() - 10)
  log.Print("Seeking second ", timeStamp)
  frameTs := gmf.Rescale(timeStamp*1000, int64(videoStream.TimeBase().AVR().Den), int64(videoStream.TimeBase().AVR().Num)) / 1000
  log.Print("Seeking timestamp ", frameTs)

  //Note here I'm using AVSEEK_FLAG_BACKWARD (int 1), but I get the same behavior
  //  with any other flag. Ideally, AVSEEK_FLAG_ANY (int 4) would work
  seekErr := fileCtx.SeekFile(videoStream, frameTs, frameTs, 1) 
ccaum commented 4 years ago

It turns out it's because of the start time on my video isn't zero. I tried it with the bbb.mp4 file in the examples directory and it worked as expected.