2022-04-06 17:46:41 +02:00
|
|
|
package ffmpeg
|
|
|
|
|
|
|
|
import (
|
2022-04-13 22:17:59 +02:00
|
|
|
"fmt"
|
2022-04-06 17:46:41 +02:00
|
|
|
"os/exec"
|
2022-04-13 22:17:59 +02:00
|
|
|
|
|
|
|
"github.com/photoprism/photoprism/pkg/fs"
|
2022-04-06 17:46:41 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// AvcConvertCommand returns the command for converting video files to MPEG-4 AVC.
|
2023-03-14 18:00:55 +01:00
|
|
|
func AvcConvertCommand(fileName, avcName string, opt Options) (result *exec.Cmd, useMutex bool, err error) {
|
2022-04-13 22:17:59 +02:00
|
|
|
if fileName == "" {
|
|
|
|
return nil, false, fmt.Errorf("empty input filename")
|
|
|
|
} else if avcName == "" {
|
|
|
|
return nil, false, fmt.Errorf("empty output filename")
|
|
|
|
}
|
2023-07-15 15:17:41 +02:00
|
|
|
|
2022-04-06 17:46:41 +02:00
|
|
|
// Don't transcode more than one video at the same time.
|
|
|
|
useMutex = true
|
|
|
|
|
2023-02-22 16:33:33 +01:00
|
|
|
// Don't use hardware transcoding for animated images.
|
|
|
|
if fs.TypeAnimated[fs.FileType(fileName)] != "" {
|
2022-04-13 22:17:59 +02:00
|
|
|
result = exec.Command(
|
2023-03-14 18:00:55 +01:00
|
|
|
opt.Bin,
|
2022-04-13 22:17:59 +02:00
|
|
|
"-i", fileName,
|
|
|
|
"-movflags", "faststart",
|
2023-07-18 15:15:04 +02:00
|
|
|
"-pix_fmt", FormatYUV420P.String(),
|
2022-04-13 22:17:59 +02:00
|
|
|
"-vf", "scale=trunc(iw/2)*2:trunc(ih/2)*2",
|
|
|
|
"-f", "mp4",
|
|
|
|
"-y",
|
|
|
|
avcName,
|
|
|
|
)
|
|
|
|
|
|
|
|
return result, useMutex, nil
|
|
|
|
}
|
2022-04-06 17:46:41 +02:00
|
|
|
|
|
|
|
// Display encoder info.
|
2023-03-14 18:00:55 +01:00
|
|
|
if opt.Encoder != SoftwareEncoder {
|
|
|
|
log.Infof("convert: ffmpeg encoder %s selected", opt.Encoder.String())
|
2022-04-06 17:46:41 +02:00
|
|
|
}
|
|
|
|
|
2023-03-14 18:00:55 +01:00
|
|
|
switch opt.Encoder {
|
2022-04-13 22:17:59 +02:00
|
|
|
case IntelEncoder:
|
|
|
|
// ffmpeg -hide_banner -h encoder=h264_qsv
|
2022-04-06 17:46:41 +02:00
|
|
|
result = exec.Command(
|
2023-03-14 18:00:55 +01:00
|
|
|
opt.Bin,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-qsv_device", "/dev/dri/renderD128",
|
|
|
|
"-i", fileName,
|
|
|
|
"-c:a", "aac",
|
2023-07-18 15:15:04 +02:00
|
|
|
"-vf", opt.VideoFilter(FormatRGB32),
|
2023-03-14 18:00:55 +01:00
|
|
|
"-c:v", opt.Encoder.String(),
|
|
|
|
"-map", opt.MapVideo,
|
|
|
|
"-map", opt.MapAudio,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-vsync", "vfr",
|
|
|
|
"-r", "30",
|
2023-03-14 18:00:55 +01:00
|
|
|
"-b:v", opt.Bitrate,
|
|
|
|
"-bitrate", opt.Bitrate,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-f", "mp4",
|
|
|
|
"-y",
|
|
|
|
avcName,
|
|
|
|
)
|
|
|
|
|
2022-04-13 22:17:59 +02:00
|
|
|
case AppleEncoder:
|
|
|
|
// ffmpeg -hide_banner -h encoder=h264_videotoolbox
|
2022-04-06 17:46:41 +02:00
|
|
|
result = exec.Command(
|
2023-03-14 18:00:55 +01:00
|
|
|
opt.Bin,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-i", fileName,
|
2023-03-14 18:00:55 +01:00
|
|
|
"-c:v", opt.Encoder.String(),
|
|
|
|
"-map", opt.MapVideo,
|
|
|
|
"-map", opt.MapAudio,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-c:a", "aac",
|
2023-07-18 15:15:04 +02:00
|
|
|
"-vf", opt.VideoFilter(FormatYUV420P),
|
2022-04-06 17:46:41 +02:00
|
|
|
"-profile", "high",
|
|
|
|
"-level", "51",
|
|
|
|
"-vsync", "vfr",
|
|
|
|
"-r", "30",
|
2023-03-14 18:00:55 +01:00
|
|
|
"-b:v", opt.Bitrate,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-f", "mp4",
|
|
|
|
"-y",
|
|
|
|
avcName,
|
|
|
|
)
|
2022-04-13 22:17:59 +02:00
|
|
|
|
2022-09-16 14:14:49 +02:00
|
|
|
case VAAPIEncoder:
|
|
|
|
result = exec.Command(
|
2023-03-14 18:00:55 +01:00
|
|
|
opt.Bin,
|
2022-09-16 14:14:49 +02:00
|
|
|
"-hwaccel", "vaapi",
|
|
|
|
"-i", fileName,
|
|
|
|
"-c:a", "aac",
|
2023-07-18 15:15:04 +02:00
|
|
|
"-vf", opt.VideoFilter(FormatNV12),
|
2023-03-14 18:00:55 +01:00
|
|
|
"-c:v", opt.Encoder.String(),
|
|
|
|
"-map", opt.MapVideo,
|
|
|
|
"-map", opt.MapAudio,
|
2022-09-16 14:14:49 +02:00
|
|
|
"-vsync", "vfr",
|
|
|
|
"-r", "30",
|
2023-03-14 18:00:55 +01:00
|
|
|
"-b:v", opt.Bitrate,
|
2022-09-16 14:14:49 +02:00
|
|
|
"-f", "mp4",
|
|
|
|
"-y",
|
|
|
|
avcName,
|
|
|
|
)
|
|
|
|
|
2022-04-13 22:17:59 +02:00
|
|
|
case NvidiaEncoder:
|
|
|
|
// ffmpeg -hide_banner -h encoder=h264_nvenc
|
2022-04-06 17:46:41 +02:00
|
|
|
result = exec.Command(
|
2023-03-14 18:00:55 +01:00
|
|
|
opt.Bin,
|
2022-11-03 16:18:04 +01:00
|
|
|
"-hwaccel", "auto",
|
2022-04-06 17:46:41 +02:00
|
|
|
"-i", fileName,
|
2023-07-18 15:15:04 +02:00
|
|
|
"-pix_fmt", FormatYUV420P.String(),
|
2023-03-14 18:00:55 +01:00
|
|
|
"-c:v", opt.Encoder.String(),
|
|
|
|
"-map", opt.MapVideo,
|
|
|
|
"-map", opt.MapAudio,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-c:a", "aac",
|
|
|
|
"-preset", "15",
|
|
|
|
"-pixel_format", "yuv420p",
|
|
|
|
"-gpu", "any",
|
2023-07-18 15:15:04 +02:00
|
|
|
"-vf", opt.VideoFilter(FormatYUV420P),
|
2022-04-06 17:46:41 +02:00
|
|
|
"-rc:v", "constqp",
|
|
|
|
"-cq", "0",
|
|
|
|
"-tune", "2",
|
2022-06-19 15:32:48 +02:00
|
|
|
"-r", "30",
|
2023-03-14 18:00:55 +01:00
|
|
|
"-b:v", opt.Bitrate,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-profile:v", "1",
|
2022-11-03 16:18:04 +01:00
|
|
|
"-level:v", "auto",
|
2022-04-06 17:46:41 +02:00
|
|
|
"-coder:v", "1",
|
|
|
|
"-f", "mp4",
|
|
|
|
"-y",
|
|
|
|
avcName,
|
|
|
|
)
|
|
|
|
|
2022-04-13 22:17:59 +02:00
|
|
|
case Video4LinuxEncoder:
|
|
|
|
// ffmpeg -hide_banner -h encoder=h264_v4l2m2m
|
2022-04-06 17:46:41 +02:00
|
|
|
result = exec.Command(
|
2023-03-14 18:00:55 +01:00
|
|
|
opt.Bin,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-i", fileName,
|
2023-03-14 18:00:55 +01:00
|
|
|
"-c:v", opt.Encoder.String(),
|
|
|
|
"-map", opt.MapVideo,
|
|
|
|
"-map", opt.MapAudio,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-c:a", "aac",
|
2023-07-18 15:15:04 +02:00
|
|
|
"-vf", opt.VideoFilter(FormatYUV420P),
|
2022-04-06 17:46:41 +02:00
|
|
|
"-num_output_buffers", "72",
|
|
|
|
"-num_capture_buffers", "64",
|
|
|
|
"-max_muxing_queue_size", "1024",
|
|
|
|
"-crf", "23",
|
|
|
|
"-vsync", "vfr",
|
|
|
|
"-r", "30",
|
2023-03-14 18:00:55 +01:00
|
|
|
"-b:v", opt.Bitrate,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-f", "mp4",
|
|
|
|
"-y",
|
|
|
|
avcName,
|
|
|
|
)
|
|
|
|
|
2022-04-13 22:17:59 +02:00
|
|
|
default:
|
2022-04-06 17:46:41 +02:00
|
|
|
result = exec.Command(
|
2023-03-14 18:00:55 +01:00
|
|
|
opt.Bin,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-i", fileName,
|
2023-03-14 18:00:55 +01:00
|
|
|
"-c:v", opt.Encoder.String(),
|
|
|
|
"-map", opt.MapVideo,
|
|
|
|
"-map", opt.MapAudio,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-c:a", "aac",
|
2023-07-18 15:15:04 +02:00
|
|
|
"-vf", opt.VideoFilter(FormatYUV420P),
|
2022-04-06 17:46:41 +02:00
|
|
|
"-max_muxing_queue_size", "1024",
|
|
|
|
"-crf", "23",
|
|
|
|
"-vsync", "vfr",
|
|
|
|
"-r", "30",
|
2023-03-14 18:00:55 +01:00
|
|
|
"-b:v", opt.Bitrate,
|
2022-04-06 17:46:41 +02:00
|
|
|
"-f", "mp4",
|
|
|
|
"-y",
|
|
|
|
avcName,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
return result, useMutex, nil
|
|
|
|
}
|