Skip to content

Commit 3b5bdf6

Browse files
committed
Cap transcode output at 1080p
1 parent 4eb3ab8 commit 3b5bdf6

4 files changed

Lines changed: 26 additions & 0 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ It is intentionally narrow: normal API traffic is forwarded to the upstream serv
1414
- Audio track selection through Emby `AudioStreamIndex`, with local transcode restart on audio changes.
1515
- Playback lifecycle tracking through Emby `/Sessions/Playing*` check-ins plus HLS access.
1616
- Conservative output target: H.264 video, AAC audio, HLS MPEG-TS segments.
17+
- Video output is capped at 1920x1080 and keeps aspect ratio.
1718

1819
Not included: virtual libraries, RSS, cover generation, scraping, database storage, or a management UI.
1920

docker/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Edit `config/config.json` before startup, or copy it to `config/config.local.jso
2626
- set `transcode.hardware_decode` to `vaapi` to use Intel or AMD VAAPI hardware decode through `/dev/dri`
2727
- startup probes VAAPI support, including device initialization, and falls back to software decode when the device, driver, or ffmpeg support is unavailable
2828
- the image includes common Intel and AMD VAAPI userspace drivers plus `vainfo`
29+
- video output is capped at 1920x1080 while preserving aspect ratio
2930

3031
For GitHub Actions publishing to Docker Hub, set `DOCKERHUB_USERNAME` and `DOCKERHUB_TOKEN` in the repository secrets.
3132

internal/transcode/ffmpeg_args_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,27 @@ func TestBuildFFmpegArgsAppliesVAAPIHardwareDecodeBeforeInput(t *testing.T) {
106106
}
107107
}
108108

109+
func TestBuildFFmpegArgsCapsVideoOutputTo1080p(t *testing.T) {
110+
session := &Session{
111+
ID: "item123",
112+
Dir: t.TempDir(),
113+
}
114+
115+
args := buildFFmpegArgs(session, Request{InputURL: "http://upstream/stream"})
116+
117+
vfIndex := slices.Index(args, "-vf")
118+
if vfIndex < 0 {
119+
t.Fatalf("missing video scale filter: %v", args)
120+
}
121+
got := args[vfIndex+1]
122+
if !strings.Contains(got, "scale=") {
123+
t.Fatalf("expected scale filter, got %q", got)
124+
}
125+
if !strings.Contains(got, "1920") || !strings.Contains(got, "1080") {
126+
t.Fatalf("expected 1080p cap in scale filter, got %q", got)
127+
}
128+
}
129+
109130
func TestBuildFFmpegArgsMapsFirstAudioStreamReturnedByEmby(t *testing.T) {
110131
session := &Session{
111132
ID: "item123",

internal/transcode/manager.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import (
2323
var ErrTooManySessions = errors.New("too many transcode sessions")
2424

2525
const defaultRestartGraceTimeout = 500 * time.Millisecond
26+
const maxTranscodeWidth = 1920
27+
const maxTranscodeHeight = 1080
2628

2729
type Options struct {
2830
MaxSessions int
@@ -933,6 +935,7 @@ func buildFFmpegArgs(session *Session, request Request, options ...FFmpegOptions
933935
"-i", request.InputURL,
934936
"-map", "0:v:0",
935937
"-map", audioMapArg(session, request),
938+
"-vf", fmt.Sprintf("scale=w=%d:h=%d:force_original_aspect_ratio=decrease:force_divisible_by=2", maxTranscodeWidth, maxTranscodeHeight),
936939
"-c:v", "libx264",
937940
"-preset", "veryfast",
938941
"-profile:v", "high",

0 commit comments

Comments
 (0)