Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ UPLOAD_MAX_BYTES=5368709120
# Transcoder (Phase 10) — limit CPU/RAM per job, sequential renditions
FFMPEG_THREADS=2
FFMPEG_PRESET=veryfast
# Phase 12: adaptive ladder + HW + pipe streaming
ENCODE_MODE=cbr
FFMPEG_HWACCEL=auto
TRANSCODER_PIPE_INPUT=true

# Services ports (infra)
POSTGRES_PORT=5432
Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# .env — единственный в корне, compose явно указывает на него (--env-file), deploy/.env не нужен
COMPOSE=docker compose --env-file .env -f deploy/docker-compose.yml

.PHONY: up down logs ps build lint fmt test e2e swagger swagger-install sync-py migrate-up migrate-down migrate-create migrate-alembic-up
.PHONY: up down logs ps build lint fmt test e2e e2e-file swagger swagger-install sync-py migrate-up migrate-down migrate-create migrate-alembic-up

up:
$(COMPOSE) up --build -d
Expand Down Expand Up @@ -106,7 +106,11 @@ fmt-front:
cd frontend && npm run format || npx prettier --write .

e2e:
bash scripts/e2e.sh
POLL_TIMEOUT="$(POLL_TIMEOUT)" SAMPLE="$(SAMPLE)" bash scripts/e2e.sh

e2e-file:
@test -n "$(FILE)" || (echo "usage: make e2e-file FILE=path/to/video.mp4" && exit 1)
POLL_TIMEOUT="$(POLL_TIMEOUT)" SAMPLE="$(FILE)" bash scripts/e2e.sh

# Migrations — single source of truth: deploy/migrations (golang-migrate)
# Prod: `migrate` service in docker-compose.yml runs `up` automatically.
Expand Down
3 changes: 3 additions & 0 deletions deploy/docker-compose.prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ services:
LOG_LEVEL: warn
FFMPEG_THREADS: ${FFMPEG_THREADS:-2}
FFMPEG_PRESET: ${FFMPEG_PRESET:-veryfast}
ENCODE_MODE: ${ENCODE_MODE:-cbr}
FFMPEG_HWACCEL: ${FFMPEG_HWACCEL:-auto}
TRANSCODER_PIPE_INPUT: ${TRANSCODER_PIPE_INPUT:-true}
deploy:
resources:
limits:
Expand Down
3 changes: 3 additions & 0 deletions deploy/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,9 @@ services:
INTERNAL_TOKEN: ${INTERNAL_TOKEN:-}
FFMPEG_THREADS: ${FFMPEG_THREADS:-2}
FFMPEG_PRESET: ${FFMPEG_PRESET:-veryfast}
ENCODE_MODE: ${ENCODE_MODE:-cbr}
FFMPEG_HWACCEL: ${FFMPEG_HWACCEL:-auto}
TRANSCODER_PIPE_INPUT: ${TRANSCODER_PIPE_INPUT:-true}
depends_on:
rabbitmq:
condition: service_healthy
Expand Down
23 changes: 21 additions & 2 deletions scripts/e2e.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,23 @@ EMAIL=${EMAIL:-user@example.com}
PASSWORD=${PASSWORD:-string}
SAMPLE=${SAMPLE:-}
VIDEO_ID=${VIDEO_ID:-}
POLL_TIMEOUT=${POLL_TIMEOUT:-240}
POLL_TIMEOUT=${POLL_TIMEOUT:-600}
POLL_INTERVAL=${POLL_INTERVAL:-3}
EXPECTED_RENDITIONS=${EXPECTED_RENDITIONS:-3}
EXPECTED_RENDITIONS=${EXPECTED_RENDITIONS:-}
# Phase 12 adaptive ladder: infer expected renditions from SAMPLE height if not set
infer_expected() {
local sample="$1"
if [ -n "$EXPECTED_RENDITIONS" ]; then echo "$EXPECTED_RENDITIONS"; return; fi
if [ -n "$sample" ] && [ -f "$sample" ] && command -v ffprobe >/dev/null 2>&1; then
local h
h=$(ffprobe -v error -select_streams v:0 -show_entries stream=height -of csv=p=0 "$sample" 2>/dev/null | head -1 | tr -d '\r' || echo "")
if [ -n "$h" ] && [ "$h" -ge 1080 ] 2>/dev/null; then echo 3; return; fi
if [ -n "$h" ] && [ "$h" -ge 720 ] 2>/dev/null; then echo 2; return; fi
if [ -n "$h" ] && [ "$h" -gt 0 ] 2>/dev/null; then echo 1; return; fi
fi
# fallback for generated 1280x720 sample or unknown
echo 2
}

TMP=$(mktemp -d)
trap 'rm -rf "$TMP"' EXIT
Expand Down Expand Up @@ -106,6 +120,11 @@ if [ -z "$VIDEO_ID" ]; then
|| fail "ffmpeg sample generation failed"
fi
[ -f "$SAMPLE" ] || fail "sample not found: $SAMPLE"
# infer expected renditions now that SAMPLE is known (Phase 12)
if [ -z "$EXPECTED_RENDITIONS" ]; then
EXPECTED_RENDITIONS=$(infer_expected "$SAMPLE")
say " inferred EXPECTED_RENDITIONS=$EXPECTED_RENDITIONS for $SAMPLE"
fi

say "3) upload $SAMPLE"
code=$(curl -s -o "$TMP/body" -w '%{http_code}' -X POST "$UPLOAD/api/v1/videos/upload" \
Expand Down
3 changes: 2 additions & 1 deletion services/metadata/internal/handler/video.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ type vodClip struct {
}

// GetVODMapping returns the nginx-vod mapped-mode representation for a ready video.
// Phase 12: adaptive ladder — accept 1..3 renditions (not fixed 3).
func (h *VideoHandler) GetVODMapping(w http.ResponseWriter, r *http.Request) {
v, err := h.repo.GetByID(r.Context(), chi.URLParam(r, "id"))
if err != nil || v.Status != model.StatusReady || len(v.Renditions) != 3 {
if err != nil || v.Status != model.StatusReady || len(v.Renditions) == 0 {
writeError(w, r, http.StatusNotFound, "video not ready")
return
}
Expand Down
2 changes: 2 additions & 0 deletions services/transcoder/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
FROM ghcr.io/astral-sh/uv:0.9-python3.14-bookworm-slim AS builder
WORKDIR /app
ENV UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
# FFmpeg CPU build; for NVENC HW accel use jrottenberg/ffmpeg:6.1-nvidia or install nvidia runtime (Phase 12)
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg curl && rm -rf /var/lib/apt/lists/*
COPY pyproject.toml uv.lock* ./
RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen --no-install-project || uv sync --no-install-project
Expand All @@ -9,6 +10,7 @@ RUN --mount=type=cache,target=/root/.cache/uv uv sync --frozen || uv sync

FROM python:3.14-slim
WORKDIR /app
# Phase 12: ffmpeg with fallback to libx264; if FFMPEG_HWACCEL=nvenc and nvidia runtime present, h264_nvenc is used
RUN apt-get update && apt-get install -y --no-install-recommends ffmpeg curl procps && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /app/app ./app
Expand Down
Loading
Loading