mirror of
https://github.com/superseriousbusiness/gotosocial
synced 2025-06-05 21:59:39 +02:00
[feature] support processing of (many) more media types (#3090)
* initial work replacing our media decoding / encoding pipeline with ffprobe + ffmpeg * specify the video codec to use when generating static image from emoji * update go-storage library (fixes incompatibility after updating go-iotools) * maintain image aspect ratio when generating a thumbnail for it * update readme to show go-ffmpreg * fix a bunch of media tests, move filesize checking to callers of media manager for more flexibility * remove extra debug from error message * fix up incorrect function signatures * update PutFile to just use regular file copy, as changes are file is on separate partition * fix remaining tests, remove some unneeded tests now we're working with ffmpeg/ffprobe * update more tests, add more code comments * add utilities to generate processed emoji / media outputs * fix remaining tests * add test for opus media file, add license header to utility cmds * limit the number of concurrently available ffmpeg / ffprobe instances * reduce number of instances * further reduce number of instances * fix envparsing test with configuration variables * update docs and configuration with new media-{local,remote}-max-size variables
This commit is contained in:
252
vendor/github.com/golang/geo/s2/paddedcell.go
generated
vendored
252
vendor/github.com/golang/geo/s2/paddedcell.go
generated
vendored
@ -1,252 +0,0 @@
|
||||
// Copyright 2016 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package s2
|
||||
|
||||
import (
|
||||
"github.com/golang/geo/r1"
|
||||
"github.com/golang/geo/r2"
|
||||
)
|
||||
|
||||
// PaddedCell represents a Cell whose (u,v)-range has been expanded on
|
||||
// all sides by a given amount of "padding". Unlike Cell, its methods and
|
||||
// representation are optimized for clipping edges against Cell boundaries
|
||||
// to determine which cells are intersected by a given set of edges.
|
||||
type PaddedCell struct {
|
||||
id CellID
|
||||
padding float64
|
||||
bound r2.Rect
|
||||
middle r2.Rect // A rect in (u, v)-space that belongs to all four children.
|
||||
iLo, jLo int // Minimum (i,j)-coordinates of this cell before padding
|
||||
orientation int // Hilbert curve orientation of this cell.
|
||||
level int
|
||||
}
|
||||
|
||||
// PaddedCellFromCellID constructs a padded cell with the given padding.
|
||||
func PaddedCellFromCellID(id CellID, padding float64) *PaddedCell {
|
||||
p := &PaddedCell{
|
||||
id: id,
|
||||
padding: padding,
|
||||
middle: r2.EmptyRect(),
|
||||
}
|
||||
|
||||
// Fast path for constructing a top-level face (the most common case).
|
||||
if id.isFace() {
|
||||
limit := padding + 1
|
||||
p.bound = r2.Rect{r1.Interval{-limit, limit}, r1.Interval{-limit, limit}}
|
||||
p.middle = r2.Rect{r1.Interval{-padding, padding}, r1.Interval{-padding, padding}}
|
||||
p.orientation = id.Face() & 1
|
||||
return p
|
||||
}
|
||||
|
||||
_, p.iLo, p.jLo, p.orientation = id.faceIJOrientation()
|
||||
p.level = id.Level()
|
||||
p.bound = ijLevelToBoundUV(p.iLo, p.jLo, p.level).ExpandedByMargin(padding)
|
||||
ijSize := sizeIJ(p.level)
|
||||
p.iLo &= -ijSize
|
||||
p.jLo &= -ijSize
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// PaddedCellFromParentIJ constructs the child of parent with the given (i,j) index.
|
||||
// The four child cells have indices of (0,0), (0,1), (1,0), (1,1), where the i and j
|
||||
// indices correspond to increasing u- and v-values respectively.
|
||||
func PaddedCellFromParentIJ(parent *PaddedCell, i, j int) *PaddedCell {
|
||||
// Compute the position and orientation of the child incrementally from the
|
||||
// orientation of the parent.
|
||||
pos := ijToPos[parent.orientation][2*i+j]
|
||||
|
||||
p := &PaddedCell{
|
||||
id: parent.id.Children()[pos],
|
||||
padding: parent.padding,
|
||||
bound: parent.bound,
|
||||
orientation: parent.orientation ^ posToOrientation[pos],
|
||||
level: parent.level + 1,
|
||||
middle: r2.EmptyRect(),
|
||||
}
|
||||
|
||||
ijSize := sizeIJ(p.level)
|
||||
p.iLo = parent.iLo + i*ijSize
|
||||
p.jLo = parent.jLo + j*ijSize
|
||||
|
||||
// For each child, one corner of the bound is taken directly from the parent
|
||||
// while the diagonally opposite corner is taken from middle().
|
||||
middle := parent.Middle()
|
||||
if i == 1 {
|
||||
p.bound.X.Lo = middle.X.Lo
|
||||
} else {
|
||||
p.bound.X.Hi = middle.X.Hi
|
||||
}
|
||||
if j == 1 {
|
||||
p.bound.Y.Lo = middle.Y.Lo
|
||||
} else {
|
||||
p.bound.Y.Hi = middle.Y.Hi
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// CellID returns the CellID this padded cell represents.
|
||||
func (p PaddedCell) CellID() CellID {
|
||||
return p.id
|
||||
}
|
||||
|
||||
// Padding returns the amount of padding on this cell.
|
||||
func (p PaddedCell) Padding() float64 {
|
||||
return p.padding
|
||||
}
|
||||
|
||||
// Level returns the level this cell is at.
|
||||
func (p PaddedCell) Level() int {
|
||||
return p.level
|
||||
}
|
||||
|
||||
// Center returns the center of this cell.
|
||||
func (p PaddedCell) Center() Point {
|
||||
ijSize := sizeIJ(p.level)
|
||||
si := uint32(2*p.iLo + ijSize)
|
||||
ti := uint32(2*p.jLo + ijSize)
|
||||
return Point{faceSiTiToXYZ(p.id.Face(), si, ti).Normalize()}
|
||||
}
|
||||
|
||||
// Middle returns the rectangle in the middle of this cell that belongs to
|
||||
// all four of its children in (u,v)-space.
|
||||
func (p *PaddedCell) Middle() r2.Rect {
|
||||
// We compute this field lazily because it is not needed the majority of the
|
||||
// time (i.e., for cells where the recursion terminates).
|
||||
if p.middle.IsEmpty() {
|
||||
ijSize := sizeIJ(p.level)
|
||||
u := stToUV(siTiToST(uint32(2*p.iLo + ijSize)))
|
||||
v := stToUV(siTiToST(uint32(2*p.jLo + ijSize)))
|
||||
p.middle = r2.Rect{
|
||||
r1.Interval{u - p.padding, u + p.padding},
|
||||
r1.Interval{v - p.padding, v + p.padding},
|
||||
}
|
||||
}
|
||||
return p.middle
|
||||
}
|
||||
|
||||
// Bound returns the bounds for this cell in (u,v)-space including padding.
|
||||
func (p PaddedCell) Bound() r2.Rect {
|
||||
return p.bound
|
||||
}
|
||||
|
||||
// ChildIJ returns the (i,j) coordinates for the child cell at the given traversal
|
||||
// position. The traversal position corresponds to the order in which child
|
||||
// cells are visited by the Hilbert curve.
|
||||
func (p PaddedCell) ChildIJ(pos int) (i, j int) {
|
||||
ij := posToIJ[p.orientation][pos]
|
||||
return ij >> 1, ij & 1
|
||||
}
|
||||
|
||||
// EntryVertex return the vertex where the space-filling curve enters this cell.
|
||||
func (p PaddedCell) EntryVertex() Point {
|
||||
// The curve enters at the (0,0) vertex unless the axis directions are
|
||||
// reversed, in which case it enters at the (1,1) vertex.
|
||||
i := p.iLo
|
||||
j := p.jLo
|
||||
if p.orientation&invertMask != 0 {
|
||||
ijSize := sizeIJ(p.level)
|
||||
i += ijSize
|
||||
j += ijSize
|
||||
}
|
||||
return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()}
|
||||
}
|
||||
|
||||
// ExitVertex returns the vertex where the space-filling curve exits this cell.
|
||||
func (p PaddedCell) ExitVertex() Point {
|
||||
// The curve exits at the (1,0) vertex unless the axes are swapped or
|
||||
// inverted but not both, in which case it exits at the (0,1) vertex.
|
||||
i := p.iLo
|
||||
j := p.jLo
|
||||
ijSize := sizeIJ(p.level)
|
||||
if p.orientation == 0 || p.orientation == swapMask+invertMask {
|
||||
i += ijSize
|
||||
} else {
|
||||
j += ijSize
|
||||
}
|
||||
return Point{faceSiTiToXYZ(p.id.Face(), uint32(2*i), uint32(2*j)).Normalize()}
|
||||
}
|
||||
|
||||
// ShrinkToFit returns the smallest CellID that contains all descendants of this
|
||||
// padded cell whose bounds intersect the given rect. For algorithms that use
|
||||
// recursive subdivision to find the cells that intersect a particular object, this
|
||||
// method can be used to skip all of the initial subdivision steps where only
|
||||
// one child needs to be expanded.
|
||||
//
|
||||
// Note that this method is not the same as returning the smallest cell that contains
|
||||
// the intersection of this cell with rect. Because of the padding, even if one child
|
||||
// completely contains rect it is still possible that a neighboring child may also
|
||||
// intersect the given rect.
|
||||
//
|
||||
// The provided Rect must intersect the bounds of this cell.
|
||||
func (p *PaddedCell) ShrinkToFit(rect r2.Rect) CellID {
|
||||
// Quick rejection test: if rect contains the center of this cell along
|
||||
// either axis, then no further shrinking is possible.
|
||||
if p.level == 0 {
|
||||
// Fast path (most calls to this function start with a face cell).
|
||||
if rect.X.Contains(0) || rect.Y.Contains(0) {
|
||||
return p.id
|
||||
}
|
||||
}
|
||||
|
||||
ijSize := sizeIJ(p.level)
|
||||
if rect.X.Contains(stToUV(siTiToST(uint32(2*p.iLo+ijSize)))) ||
|
||||
rect.Y.Contains(stToUV(siTiToST(uint32(2*p.jLo+ijSize)))) {
|
||||
return p.id
|
||||
}
|
||||
|
||||
// Otherwise we expand rect by the given padding on all sides and find
|
||||
// the range of coordinates that it spans along the i- and j-axes. We then
|
||||
// compute the highest bit position at which the min and max coordinates
|
||||
// differ. This corresponds to the first cell level at which at least two
|
||||
// children intersect rect.
|
||||
|
||||
// Increase the padding to compensate for the error in uvToST.
|
||||
// (The constant below is a provable upper bound on the additional error.)
|
||||
padded := rect.ExpandedByMargin(p.padding + 1.5*dblEpsilon)
|
||||
iMin, jMin := p.iLo, p.jLo // Min i- or j- coordinate spanned by padded
|
||||
var iXor, jXor int // XOR of the min and max i- or j-coordinates
|
||||
|
||||
if iMin < stToIJ(uvToST(padded.X.Lo)) {
|
||||
iMin = stToIJ(uvToST(padded.X.Lo))
|
||||
}
|
||||
if a, b := p.iLo+ijSize-1, stToIJ(uvToST(padded.X.Hi)); a <= b {
|
||||
iXor = iMin ^ a
|
||||
} else {
|
||||
iXor = iMin ^ b
|
||||
}
|
||||
|
||||
if jMin < stToIJ(uvToST(padded.Y.Lo)) {
|
||||
jMin = stToIJ(uvToST(padded.Y.Lo))
|
||||
}
|
||||
if a, b := p.jLo+ijSize-1, stToIJ(uvToST(padded.Y.Hi)); a <= b {
|
||||
jXor = jMin ^ a
|
||||
} else {
|
||||
jXor = jMin ^ b
|
||||
}
|
||||
|
||||
// Compute the highest bit position where the two i- or j-endpoints differ,
|
||||
// and then choose the cell level that includes both of these endpoints. So
|
||||
// if both pairs of endpoints are equal we choose maxLevel; if they differ
|
||||
// only at bit 0, we choose (maxLevel - 1), and so on.
|
||||
levelMSB := uint64(((iXor | jXor) << 1) + 1)
|
||||
level := maxLevel - findMSBSetNonZero64(levelMSB)
|
||||
if level <= p.level {
|
||||
return p.id
|
||||
}
|
||||
|
||||
return cellIDFromFaceIJ(p.id.Face(), iMin, jMin).Parent(level)
|
||||
}
|
Reference in New Issue
Block a user