diff --git a/README.md b/README.md index b27e6d5..27b06ca 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Build and push this container to ghcr - [ ] change from Audio -> Video - [x] Provide a better name for downloaded files - [x] Environment variable to control whether "Secure" flag set on cookie -- [ ] Allow custom FPS for video transcode +- [x] Allow custom FPS for video transcode - [ ] Provide an about page - `ffmpeg` version - `yt-dlp` version diff --git a/handlers.go b/handlers.go index 90e7504..1c1fe28 100644 --- a/handlers.go +++ b/handlers.go @@ -486,13 +486,14 @@ func addAudioTranscode(mediaId, originalId, bitrate uint, srcKind string) { db.Create(&t) } -func addVideoTranscode(videoId, originalId, targetHeight uint) { +func addVideoTranscode(videoId, originalId, targetHeight uint, targetFPS float64) { t := Transcode{ SrcID: videoId, OriginalID: originalId, SrcKind: "video", DstKind: "video", Height: targetHeight, + FPS: targetFPS, TimeSubmit: time.Now(), Status: "pending", } @@ -532,7 +533,7 @@ func processOriginal(originalID uint) { // create video transcodes for _, targetHeight := range []uint{480, 240, 144} { if targetHeight <= video.Height { - addVideoTranscode(video.ID, originalID, targetHeight) + addVideoTranscode(video.ID, originalID, targetHeight, video.FPS) break } } @@ -1045,6 +1046,7 @@ func deleteAudioHandler(c echo.Context) error { func transcodeToVideoHandler(c echo.Context) error { originalId, _ := strconv.ParseUint(c.FormValue("original_id"), 10, 32) height, _ := strconv.ParseUint(c.FormValue("height"), 10, 32) + fps, _ := strconv.ParseFloat(c.FormValue("fps"), 64) referrer := c.Request().Referer() if referrer == "" { referrer = "/" @@ -1055,7 +1057,7 @@ func transcodeToVideoHandler(c echo.Context) error { if err == gorm.ErrRecordNotFound { log.Errorf("no video record for original %d: %v", originalId, err) } else { - addVideoTranscode(video.ID, uint(originalId), uint(height)) + addVideoTranscode(video.ID, uint(originalId), uint(height), fps) } return c.Redirect(http.StatusSeeOther, referrer) diff --git a/models.go b/models.go index d021d37..d8a6104 100644 --- a/models.go +++ b/models.go @@ -23,9 +23,9 @@ type Transcode struct { TimeStart time.Time // video fields - Height uint // target height - Width uint // target width - FPS uint // target FPS + Height uint // target height + Width uint // target width + FPS float64 // target FPS // audio & video fields Rate uint diff --git a/templates/video.html b/templates/video.html index 6f978d8..8c47914 100644 --- a/templates/video.html +++ b/templates/video.html @@ -55,6 +55,7 @@ + diff --git a/workers.go b/workers.go index e3f3d83..3c08e61 100644 --- a/workers.go +++ b/workers.go @@ -19,7 +19,7 @@ func ensureDirFor(path string) error { return os.MkdirAll(dir, 0700) } -func videoToVideo(transID uint, height uint, srcFilepath string) { +func videoToVideo(transID uint, height uint, fps float64, srcFilepath string) { // determine destination path dstFilename := uuid.Must(uuid.NewV7()).String() @@ -47,8 +47,14 @@ func videoToVideo(transID uint, height uint, srcFilepath string) { // start ffmpeg db.Model(&Transcode{}).Where("id = ?", transID).Update("status", "running") + var vf string + if fps > 0 { + vf = fmt.Sprintf("scale=-2:%d,fps=%f", height, fps) + } else { + vf = fmt.Sprintf("scale=-2:%d", height) + } stdout, stderr, err := ffmpeg.Ffmpeg("-i", srcFilepath, - "-vf", fmt.Sprintf("scale=-2:%d", height), "-c:v", "libx264", + "-vf", vf, "-c:v", "libx264", "-crf", "23", "-preset", "veryfast", "-c:a", "aac", "-b:a", fmt.Sprintf("%dk", audioBitrate), dstFilepath) if err != nil { @@ -258,7 +264,7 @@ func transcodePending() { srcFilepath := filepath.Join(getDataDir(), srcVideo.Filename) if trans.DstKind == "video" { - videoToVideo(trans.ID, trans.Height, srcFilepath) + videoToVideo(trans.ID, trans.Height, trans.FPS, srcFilepath) } else if trans.DstKind == "audio" { videoToAudio(trans.ID, trans.Rate, srcFilepath) } else {