better trnscode
This commit is contained in:
parent
e7255ea8a2
commit
8e7944f688
5 changed files with 75 additions and 14 deletions
|
|
@ -9,6 +9,7 @@ RUN git clone https://github.com/m1k1o/go-transcode.git . \
|
||||||
|
|
||||||
COPY patches/go-transcode-vaapi.patch /tmp/go-transcode-vaapi.patch
|
COPY patches/go-transcode-vaapi.patch /tmp/go-transcode-vaapi.patch
|
||||||
RUN git apply /tmp/go-transcode-vaapi.patch \
|
RUN git apply /tmp/go-transcode-vaapi.patch \
|
||||||
|
&& gofmt -w hlsvod/manager.go hlsvod/probe.go hlsvod/transcode.go \
|
||||||
&& CGO_ENABLED=0 go build -o /go-transcode .
|
&& CGO_ENABLED=0 go build -o /go-transcode .
|
||||||
|
|
||||||
# Keep Alpine 3.17: upstream documents an FFmpeg 6 segmenting regression with
|
# Keep Alpine 3.17: upstream documents an FFmpeg 6 segmenting regression with
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,8 @@ vod:
|
||||||
transcode-dir: /tmp/go-transcode
|
transcode-dir: /tmp/go-transcode
|
||||||
cache: true
|
cache: true
|
||||||
cache-dir: /cache
|
cache-dir: /cache
|
||||||
video-keyframes: true
|
# Avoid expensive full-file keyframe scans. FFmpeg forces HLS boundaries.
|
||||||
|
video-keyframes: false
|
||||||
video-profiles:
|
video-profiles:
|
||||||
480p:
|
480p:
|
||||||
width: 854
|
width: 854
|
||||||
|
|
|
||||||
|
|
@ -20,13 +20,14 @@ services:
|
||||||
- /dev/dri:/dev/dri
|
- /dev/dri:/dev/dri
|
||||||
environment:
|
environment:
|
||||||
- TRANSCODE_VAAPI_DEVICE=/dev/dri/renderD128
|
- TRANSCODE_VAAPI_DEVICE=/dev/dri/renderD128
|
||||||
|
- LIBVA_DRIVER_NAME=i965
|
||||||
volumes:
|
volumes:
|
||||||
- /mnt/user/plex:/media:ro
|
- /mnt/user/plex:/media:ro
|
||||||
- ./transcode-config.yaml:/app/config.yaml:ro
|
- ./transcode-config.yaml:/app/config.yaml:ro
|
||||||
- transcode-cache:/cache
|
- transcode-cache-v3:/cache
|
||||||
ports:
|
ports:
|
||||||
- "8090:8080"
|
- "8090:8080"
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
transcode-cache:
|
transcode-cache-v3:
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,88 @@
|
||||||
|
diff --git a/hlsvod/manager.go b/hlsvod/manager.go
|
||||||
|
index 662c41d..51460f8 100644
|
||||||
|
--- a/hlsvod/manager.go
|
||||||
|
+++ b/hlsvod/manager.go
|
||||||
|
@@ -378,12 +378,17 @@ func (m *ManagerCtx) waitForSegment(index int) (chan struct{}, bool) {
|
||||||
|
|
||||||
|
func (m *ManagerCtx) transcodeSegments(offset, limit int) error {
|
||||||
|
logger := m.logger.With().Int("offset", offset).Int("limit", limit).Logger()
|
||||||
|
+ inputCodec := ""
|
||||||
|
+ if m.metadata.Video != nil {
|
||||||
|
+ inputCodec = m.metadata.Video.CodecName
|
||||||
|
+ }
|
||||||
|
|
||||||
|
segmentTimes := m.breakpoints[offset : offset+limit+1]
|
||||||
|
logger.Info().Interface("segments-times", segmentTimes).Msg("transcoding segments")
|
||||||
|
|
||||||
|
segments, err := TranscodeSegments(m.ctx, m.config.FFmpegBinary, TranscodeConfig{
|
||||||
|
InputFilePath: m.config.MediaPath,
|
||||||
|
+ InputCodec: inputCodec,
|
||||||
|
OutputDirPath: m.config.TranscodeDir,
|
||||||
|
SegmentPrefix: m.config.SegmentPrefix, // This does not need to match.
|
||||||
|
|
||||||
|
diff --git a/hlsvod/probe.go b/hlsvod/probe.go
|
||||||
|
index c39461c..58c3edd 100644
|
||||||
|
--- a/hlsvod/probe.go
|
||||||
|
+++ b/hlsvod/probe.go
|
||||||
|
@@ -83,6 +83,7 @@ func ProbeMedia(ctx context.Context, ffprobeBinary string, inputFilePath string)
|
||||||
|
}
|
||||||
|
|
||||||
|
data.Video = &ProbeVideoData{
|
||||||
|
+ CodecName: stream.CodecName,
|
||||||
|
Width: stream.Width,
|
||||||
|
Height: stream.Height,
|
||||||
|
Duration: duration,
|
||||||
|
@@ -118,6 +119,7 @@ func ProbeMedia(ctx context.Context, ffprobeBinary string, inputFilePath string)
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProbeVideoData struct {
|
||||||
|
+ CodecName string
|
||||||
|
Width int
|
||||||
|
Height int
|
||||||
|
Duration time.Duration
|
||||||
diff --git a/hlsvod/transcode.go b/hlsvod/transcode.go
|
diff --git a/hlsvod/transcode.go b/hlsvod/transcode.go
|
||||||
index 1b04b00..12eb935 100644
|
index 9bbe037..c0297fe 100644
|
||||||
--- a/hlsvod/transcode.go
|
--- a/hlsvod/transcode.go
|
||||||
+++ b/hlsvod/transcode.go
|
+++ b/hlsvod/transcode.go
|
||||||
@@ -6,5 +6,6 @@ import (
|
@@ -5,6 +5,7 @@ import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
+ "os"
|
+ "os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -56,6 +57,16 @@ func TranscodeSegments(ctx context.Context, ffmpegBinary string, config Transcod
|
@@ -13,6 +14,7 @@ import (
|
||||||
|
|
||||||
|
type TranscodeConfig struct {
|
||||||
|
InputFilePath string // Transcoded video input.
|
||||||
|
+ InputCodec string // ffprobe codec name, e.g. h264 or hevc.
|
||||||
|
OutputDirPath string // Segments output path.
|
||||||
|
SegmentPrefix string // e.g. prefix-000001.ts
|
||||||
|
SegmentOffset int // Start segment number.
|
||||||
|
@@ -69,6 +71,21 @@ func TranscodeSegments(ctx context.Context, ffmpegBinary string, config Transcod
|
||||||
}...)
|
}...)
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // Decode and filter on the GPU when a VAAPI render device is configured.
|
+ // Haswell can decode H.264 in hardware, but not HEVC Main 10. Use full
|
||||||
+ // This is opt-in so upstream's software behavior remains available.
|
+ // hardware transcoding for H.264 and software decode plus VAAPI upload for
|
||||||
|
+ // other codecs. Scaling and H.264 encoding always remain on the GPU.
|
||||||
+ vaapiDevice := os.Getenv("TRANSCODE_VAAPI_DEVICE")
|
+ vaapiDevice := os.Getenv("TRANSCODE_VAAPI_DEVICE")
|
||||||
|
+ hardwareDecode := vaapiDevice != "" && config.InputCodec == "h264"
|
||||||
+ if vaapiDevice != "" {
|
+ if vaapiDevice != "" {
|
||||||
+ args = append(args, []string{
|
+ args = append(args, []string{
|
||||||
+ "-init_hw_device", "vaapi=va:" + vaapiDevice,
|
+ "-init_hw_device", "vaapi=va:" + vaapiDevice,
|
||||||
+ "-filter_hw_device", "va", "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi",
|
+ "-filter_hw_device", "va",
|
||||||
+ }...)
|
+ }...)
|
||||||
|
+ if hardwareDecode {
|
||||||
|
+ args = append(args, "-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi")
|
||||||
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
// Input specs
|
// Input specs
|
||||||
args = append(args, []string{
|
args = append(args, []string{
|
||||||
"-i", config.InputFilePath, // Input file
|
"-i", config.InputFilePath, // Input file
|
||||||
@@ -79,17 +89,26 @@ func TranscodeSegments(ctx context.Context, ffmpegBinary string, config Transcod
|
@@ -89,14 +106,26 @@ func TranscodeSegments(ctx context.Context, ffmpegBinary string, config Transcod
|
||||||
if profile.Width >= profile.Height {
|
|
||||||
scale = fmt.Sprintf("scale=-2:%d", profile.Height)
|
|
||||||
} else {
|
|
||||||
scale = fmt.Sprintf("scale=%d:-2", profile.Width)
|
scale = fmt.Sprintf("scale=%d:-2", profile.Width)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +100,9 @@ index 1b04b00..12eb935 100644
|
||||||
+ } else {
|
+ } else {
|
||||||
+ scale = fmt.Sprintf("scale_vaapi=w=%d:h=-2:format=nv12", profile.Width)
|
+ scale = fmt.Sprintf("scale_vaapi=w=%d:h=-2:format=nv12", profile.Width)
|
||||||
+ }
|
+ }
|
||||||
|
+ if !hardwareDecode {
|
||||||
|
+ scale = "format=nv12,hwupload," + scale
|
||||||
|
+ }
|
||||||
+ args = append(args, []string{
|
+ args = append(args, []string{
|
||||||
+ "-vf", scale, "-c:v", "h264_vaapi", "-profile:v", "high",
|
+ "-vf", scale, "-c:v", "h264_vaapi", "-profile:v", "high",
|
||||||
+ "-level:v", "4.0", "-b:v", fmt.Sprintf("%dk", profile.Bitrate),
|
+ "-level:v", "4.0", "-b:v", fmt.Sprintf("%dk", profile.Bitrate),
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ vod:
|
||||||
media-dir: /media
|
media-dir: /media
|
||||||
cache: true
|
cache: true
|
||||||
cache-dir: /cache
|
cache-dir: /cache
|
||||||
video-keyframes: true
|
# Full-file keyframe probing is expensive and can be OOM-killed on Unraid.
|
||||||
|
# FFmpeg will force segment-boundary keyframes during transcoding instead.
|
||||||
|
video-keyframes: false
|
||||||
|
|
||||||
video-profiles:
|
video-profiles:
|
||||||
1080p:
|
1080p:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue