Skip to content

Commit

Permalink
Scanner: Remove black bars on thumbnails (#810)
Browse files Browse the repository at this point in the history
* Scanner: Crop black bars on thumbnails

* Docker: Scanner: Move to alpine to get a newer ffmpeg version
  • Loading branch information
Arthi-chaud authored Dec 25, 2024
1 parent 7fe4de6 commit 95dc125
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 15 deletions.
9 changes: 4 additions & 5 deletions scanner/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
FROM golang:1.22.6-bullseye AS builder
FROM golang:1.22.6-alpine AS builder
RUN go install github.com/swaggo/swag/cmd/swag@latest
RUN apt-get update -y; apt-get install -y ffmpeg
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
Expand All @@ -9,12 +8,12 @@ COPY ./internal ./internal
RUN swag init -d app -o ./app/docs
RUN GOOS=linux go build -o ./scanner ./app

FROM debian:bullseye-slim AS runner
FROM golang:1.22.6-alpine AS runner

ENV SERVICE_NAME="scanner"
RUN useradd -ms /bin/false $SERVICE_NAME
RUN adduser --disabled-password -s /bin/false $SERVICE_NAME

RUN apt-get update -y; apt-get install -y ffmpeg wget libchromaprint-tools libchromaprint-dev libfftw3-dev
RUN apk update && apk upgrade && apk add ffmpeg chromaprint mailcap
WORKDIR /app
COPY --from=builder /app/scanner ./
USER $SERVICE_NAME
Expand Down
5 changes: 3 additions & 2 deletions scanner/Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
FROM golang:1.22.6-bullseye
FROM golang:1.22.6-alpine
RUN go install github.com/bokwoon95/wgo@latest
RUN go install github.com/swaggo/swag/cmd/swag@latest
RUN apt-get update -y; apt-get install -y ffmpeg libchromaprint-tools libchromaprint-dev libfftw3-dev

RUN apk update && apk upgrade && apk add ffmpeg chromaprint mailcap
WORKDIR /app

CMD ["wgo", "-xdir", "./app/docs", "swag", "init", "-d", "app", "-o", "./app/docs", "::", "go", "run", "./app"]
111 changes: 103 additions & 8 deletions scanner/internal/illustration/thumbnail.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,113 @@ package illustration
import (
"bytes"
"fmt"

"github.com/kpango/glg"
"github.com/u2takey/ffmpeg-go"
"strings"
)

type CropDimensions struct {
width int
height int
x int
y int
}

func GetFrame(filepath string, timestamp int64) ([]byte, error) {
formattedDuration := fmt.Sprintf("%.2d:%.2d:%.2d", int(timestamp/3600), (timestamp/60)%60, timestamp%60)
buf := bytes.NewBuffer(nil)
err := ffmpeg_go.Input(filepath, ffmpeg_go.KwArgs{"ss": formattedDuration}).
thumbnail := bytes.NewBuffer(nil)
filters := []string{
"scale='max(iw,iw*sar)':'max(ih,ih/sar)'",
"select=gte(n\\,1)",
}

cmd := ffmpeg_go.Input(filepath, ffmpeg_go.KwArgs{"ss": formattedDuration}).
Silent(true).
Output("pipe:", ffmpeg_go.KwArgs{
"vframes": 1,
"format": "image2",
"vcodec": "mjpeg",
"vf": strings.Join(filters, ", ")}).
WithOutput(thumbnail)
err := cmd.Run()
if err != nil {
glg.Error(err)
return nil, err
}
thumbnailBytes := thumbnail.Bytes()
croppedThumbnail, _ := RemoveBlackBars(&thumbnailBytes)
if croppedThumbnail != nil {
return croppedThumbnail.Bytes(), nil
}
return thumbnailBytes, err
}

func RemoveBlackBars(frame *[]byte) (*bytes.Buffer, error) {

crops, err := GetCropDimensions(bytes.NewBuffer(*frame))
if err != nil || crops == nil {
if err != nil {
glg.Error(err)
}
return nil, err
}
newFrame := bytes.NewBuffer(nil)
err = ffmpeg_go.Input("pipe:", ffmpeg_go.KwArgs{"format": "image2pipe"}).
Filter("crop", ffmpeg_go.Args{fmt.Sprintf("%d:%d:%d:%d", crops.width, crops.height, crops.x, crops.y)}).
Output("pipe:", ffmpeg_go.KwArgs{
"format": "image2",
"vframes": "1",
"vcodec": "mjpeg"}).
WithInput(bytes.NewBuffer(*frame)).
WithOutput(newFrame).Run()
if err != nil {
glg.Error(err)
return nil, err
}
return newFrame, err
}

func GetCropDimensions(thumbnail *bytes.Buffer) (*CropDimensions, error) {

rawout := bytes.NewBuffer(nil)

err := ffmpeg_go.Input("pipe:", ffmpeg_go.KwArgs{"f": "image2pipe", "loop": "1"}).
Silent(true).
Filter("scale", ffmpeg_go.Args{"'max(iw,iw*sar)':'max(ih,ih/sar)'"}).
Filter("select", ffmpeg_go.Args{"gte(n,1)"}).
Output("pipe:", ffmpeg_go.KwArgs{"vframes": 1, "format": "image2", "vcodec": "mjpeg"}).
WithOutput(buf).Run()
return buf.Bytes(), err
Output("pipe:", ffmpeg_go.KwArgs{
"f": "null",
"frames:v": "3",
"vf": "cropdetect=limit=0:round=0"}).
WithErrorOutput(rawout).
WithInput(thumbnail).
WithOutput(rawout).Run()
if err != nil {
glg.Error(err)
return nil, err
}
strout := string((*rawout).Bytes())
lines := strings.Split(strout, "\n")
lineCount := len(lines)
if lineCount == 0 {
return nil, nil
}
for index := lineCount; index > 0; index-- {
token := "crop="
line := lines[index-1]
cropPos := strings.Index(line, token)
if cropPos == -1 {
continue
}
dims := CropDimensions{}
_, err = fmt.Sscanf(line[cropPos+len(token):], "%d:%d:%d:%d",
&dims.width, &dims.height, &dims.x, &dims.y)
if err != nil {
glg.Error(err)
continue
}
if dims.width < 0 || dims.height < 0 {
continue
}
return &dims, nil
}
return nil, nil
}

0 comments on commit 95dc125

Please sign in to comment.