Ignite/cli/encode-server/encode.go
DataHoarder 883dad8b84
All checks were successful
continuous-integration/drone/push Build is passing
Add ffmpeg cli decoder, default env variables for VMAF_MODEL_PATH / FFMPEG_PATH
2023-11-04 15:13:39 +01:00

148 lines
3.6 KiB
Go

package main
import (
"compress/bzip2"
"compress/flate"
"compress/gzip"
"errors"
"fmt"
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
"github.com/ulikunitz/xz"
"io"
"log"
"maps"
"net/http"
"os"
"time"
)
func handleDecompress(contentEncoding string, reader io.ReadCloser) (io.ReadCloser, error) {
var err error
switch contentEncoding {
case "gzip":
reader, err = gzip.NewReader(reader)
if err != nil {
return nil, err
}
case "bzip2":
reader = io.NopCloser(bzip2.NewReader(reader))
case "deflate":
reader = flate.NewReader(reader)
case "xz":
r, err := xz.NewReader(reader)
if err != nil {
return nil, err
}
reader = io.NopCloser(r)
case "":
return reader, nil
default:
return nil, errors.New("unsupported encoding")
}
return reader, nil
}
func encodeFromReader(reader io.ReadCloser, job *Job, inputMimeType string, w http.ResponseWriter) {
defer reader.Close()
d := GetDecoderByMimeType(inputMimeType)
if d == nil {
//try for generic reader
d = GetDecoderByMimeType("*")
if d == nil {
w.WriteHeader(http.StatusBadRequest)
return
}
}
defer func() {
log.Printf("[job %s] finished, took %s", job.Id, time.Now().Sub(time.Unix(int64(job.Status.Start.Load()), 0)))
}()
job.Status.Start.Store(uint64(time.Now().Unix()))
job.Status.Read.Store(0)
job.Status.Processed.Store(0)
settings := make(map[string]any)
maps.Copy(settings, job.Config.Decoder.Settings)
if len(job.Config.Timecodes) > 0 {
settings["timecodes"] = job.Config.Timecodes
}
decoder, err := d.New(reader, settings)
if err != nil {
job.Logger.Printf("[error]: %s", err.Error())
w.Header().Set("x-encoder-error", "")
w.Header().Set("x-decoder-error", err.Error())
w.WriteHeader(http.StatusBadRequest)
return
}
//check decoder frame properties match
decProps := decoder.Properties()
if decProps.Width != job.Config.Properties.Width ||
decProps.Height != job.Config.Properties.Height ||
decProps.ColorSpace != job.Config.Properties.ColorSpace ||
decProps.FullColorRange != job.Config.Properties.FullColorRange ||
decProps.TimeBase() != job.Config.Properties.TimeBase() {
w.Header().Set("x-encoder-error", "")
w.Header().Set("x-decoder-error", "mismatched config properties")
w.WriteHeader(http.StatusBadRequest)
return
}
mimeType := "application/octet-stream"
if e := GetEncoder(job.Config.Encoder.Name); e != nil {
mimeType = e.MimeType
}
w.Header().Set("Content-Type", mimeType)
w.Header().Add("Trailer", "x-encoder-error, x-decoder-error")
w.WriteHeader(http.StatusOK)
job.Logger = log.New(os.Stderr, fmt.Sprintf("[job %s] ", job.Id), log.LstdFlags)
err = job.Init(w)
if err != nil {
job.Logger.Printf("[error]: %s", err.Error())
w.Header().Set("x-encoder-error", err.Error())
w.Header().Set("x-decoder-error", "")
return
}
defer job.Close()
var f frame.Frame
for {
f, err = decoder.Decode()
if err != nil {
if errors.Is(err, io.EOF) {
//we are done
break
}
job.Logger.Printf("[error]: %s", err.Error())
w.Header().Set("x-encoder-error", "")
w.Header().Set("x-decoder-error", err.Error())
return
}
job.Status.Read.Add(1)
err = job.Encoder.Encode(f)
if err != nil {
job.Logger.Printf("[error]: %s", err.Error())
w.Header().Set("x-encoder-error", err.Error())
w.Header().Set("x-decoder-error", "")
return
}
f.Return()
job.Status.Processed.Add(1)
//log.Printf("[job %s] %d", job.Id, job.Status.Read.Load())
}
err = job.Encoder.Flush()
if err != nil {
job.Logger.Printf("[error]: %s", err.Error())
w.Header().Set("x-encoder-error", err.Error())
w.Header().Set("x-decoder-error", "")
return
}
}