Ignite/cli/encode-server/encode.go

125 lines
3 KiB
Go

package main
import (
"compress/bzip2"
"compress/flate"
"compress/gzip"
"errors"
"fmt"
"git.gammaspectra.live/S.O.N.G/Ignite/decoder/y4m"
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
"github.com/ulikunitz/xz"
"io"
"log"
"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, w http.ResponseWriter) {
defer reader.Close()
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)
if len(job.Config.Timecodes) > 0 {
settings["timecodes"] = job.Config.Timecodes
}
decoder, err := y4m.NewDecoder(reader, settings)
if err != nil {
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
}
w.Header().Set("Content-Type", "application/octet-stream")
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 {
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
}
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 {
w.Header().Set("x-encoder-error", err.Error())
w.Header().Set("x-decoder-error", "")
return
}
job.Status.Processed.Add(1)
//log.Printf("[job %s] %d", job.Id, job.Status.Read.Load())
}
err = job.Encoder.Flush()
if err != nil {
w.Header().Set("x-encoder-error", err.Error())
w.Header().Set("x-decoder-error", "")
return
}
}