Skip to content

Commit

Permalink
Use last audio pts time for duration
Browse files Browse the repository at this point in the history
  • Loading branch information
zoriya committed Aug 27, 2024
1 parent 5c8260b commit 37921b8
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 3 deletions.
2 changes: 1 addition & 1 deletion transcoder/src/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type Audio struct {
IsDefault bool `json:"isDefault"`

/// Keyframes of this video
Keyframes *Keyframe `json:"-"`
Keyframes *Keyframe `json:"keyframes"`

//TODO: remove this in next major
IsForced bool `json:"isForced"`
Expand Down
55 changes: 53 additions & 2 deletions transcoder/src/keyframes.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package src

import (
"bufio"
"errors"
"fmt"
"log"
"os/exec"
Expand All @@ -12,7 +13,7 @@ import (
"github.com/lib/pq"
)

const KeyframeVersion = 1
const KeyframeVersion = 5

type Keyframe struct {
Keyframes []float64
Expand Down Expand Up @@ -237,8 +238,58 @@ func getVideoKeyframes(path string, video_idx uint32, kf *Keyframe) error {

// we can pretty much cut audio at any point so no need to get specific frames, just cut every 4s
func getAudioKeyframes(info *MediaInfo, audio_idx uint32, kf *Keyframe) error {
defer printExecTime("ffprobe keyframe analysis for %s audio n%d", info.Path, audio_idx)()
// Format's duration CAN be different than audio's duration. To make sure we do not
// miss a segment or make one more, we need to check the audio's duration.
//
// Some formats DO NOT contain this metadata, we need to manually fetch it from the packets.
//
// We could use the same command to retrieve all packets and know when we can cut PRECISELY
// but since packets always contain only a few ms we don't need this precision.
cmd := exec.Command(
"ffprobe",
"-select_streams", fmt.Sprintf("a:%d", audio_idx),
"-show_entries", "packet=pts_time",
// some avi files don't have pts, we use this to ask ffmpeg to generate them (it uses the dts under the hood)
"-fflags", "+genpts",
// We use a read_interval LARGER than the file (at least we estimate)
// This allows us to only decode the LAST packets
"-read_intervals", fmt.Sprintf("%f", info.Duration+10_000),
"-of", "csv=print_section=0",
info.Path,
)
stdout, err := cmd.StdoutPipe()
if err != nil {
return err
}
err = cmd.Start()
if err != nil {
return err
}

scanner := bufio.NewScanner(stdout)
var duration float64
for scanner.Scan() {
pts := scanner.Text()
if pts == "" || pts == "N/A" {
continue
}

duration, err = strconv.ParseFloat(pts, 64)
if err != nil {
return err
}

}
if err := scanner.Err(); err != nil {
return err
}
if duration <= 0 {
return errors.New("could not find audio's duration")
}

dummyKeyframeDuration := float64(4)
segmentCount := int((float64(info.Duration) / dummyKeyframeDuration) + 1)
segmentCount := int((duration / dummyKeyframeDuration) + 1)
kf.Keyframes = make([]float64, segmentCount)
for segmentIndex := 0; segmentIndex < segmentCount; segmentIndex += 1 {
kf.Keyframes[segmentIndex] = float64(segmentIndex) * dummyKeyframeDuration
Expand Down

0 comments on commit 37921b8

Please sign in to comment.